/*
 * @Author       : Bing Chen chenbing@iocharger.com
 * @Date         : 2024-05-31 11:32:16
 * @LastEditors  : Bing Chen chenbing@iocharger.com
 * @LastEditTime : 2025-03-15 12:37:31
 * @FilePath     : \openchaoji-corelib\evcc\gbt27930\OpenChaoJi_evcc_gbt27930_a.c
 * @Description  : evcc的GB/T 27930 A类系统主实现
 *
 * Copyright (c) 2025 OpenChaoJi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the icense for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include "../include/OpenChaoJi_evcc.h"

#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_A == CONFIG_YES)

struct OpenChaoJi_evcc_gbt27930_a_data
{
    struct {
        int dummy;
    } idle;

    struct {
        int time_sync;              // 时钟同步标识
        int param_update_delay;     // 变更BCP参数后，延续发送BCP报文2次以上
    } config;

    struct {
        int send_bst;               // 首次发送BST报文标识
        int bst_notice_delay;       // 充电机主动中止充电，收到CST报文后，延续发送BST报文5-10次
        struct OpenChaoJi_evcc_gbt27930_charging_requirement_parameter requirement_parameter; // 车辆请求参数
    } charge;

    int protocol_version;           // 对端通信协议版本
    int reconnect_flag;             // 通信重连标识
    int stop_status;                // 停机泄放状态
    int stop_ticks;                 // 停机超时时间
    int end_code;                   // 停机代码

    struct OpenChaoJi_evcc_app_start_parameter app_start_parameter;

    struct OpenChaoJi_os_soft_timer tvp_bhm;
    struct OpenChaoJi_os_soft_timer tvp_brm;
    struct OpenChaoJi_os_soft_timer tvp_bcp;
    struct OpenChaoJi_os_soft_timer tvp_bro;
    struct OpenChaoJi_os_soft_timer tvp_bcl;
    struct OpenChaoJi_os_soft_timer tvp_bcs;
    struct OpenChaoJi_os_soft_timer tvp_bsm;
    struct OpenChaoJi_os_soft_timer tvp_bmv;
    struct OpenChaoJi_os_soft_timer tvp_bmt;
    struct OpenChaoJi_os_soft_timer tvp_bsp;
    struct OpenChaoJi_os_soft_timer tvp_bst;
    struct OpenChaoJi_os_soft_timer tvp_bsd;
    struct OpenChaoJi_os_soft_timer tvp_bem;

    struct OpenChaoJi_os_soft_timer tvo_chm;
    struct OpenChaoJi_os_soft_timer tvo_crm_00;
    struct OpenChaoJi_os_soft_timer tvo_crm_aa;
    struct OpenChaoJi_os_soft_timer tvo_cml;
    struct OpenChaoJi_os_soft_timer tvo_cts;
    struct OpenChaoJi_os_soft_timer tvo_cro;
    struct OpenChaoJi_os_soft_timer tvo_cro_aa;
    struct OpenChaoJi_os_soft_timer tvo_ccs;
    struct OpenChaoJi_os_soft_timer tvo_cst;
    struct OpenChaoJi_os_soft_timer tvo_csd;

    struct OpenChaoJi_os_soft_timer tvo_bslp;
    struct OpenChaoJi_os_soft_timer tvo_bep;
    struct OpenChaoJi_os_soft_timer tvo_crm;
    struct OpenChaoJi_os_soft_timer tvo_csup;
    struct OpenChaoJi_os_soft_timer tvo_stopping;

    struct OpenChaoJi_gbt27930_a_msg_chm msg_chm;
    struct OpenChaoJi_gbt27930_a_msg_crm msg_crm;
    struct OpenChaoJi_gbt27930_a_msg_cts msg_cts;
    struct OpenChaoJi_gbt27930_a_msg_cml msg_cml;
    struct OpenChaoJi_gbt27930_a_msg_cro msg_cro;
    struct OpenChaoJi_gbt27930_a_msg_ccs msg_ccs;
    struct OpenChaoJi_gbt27930_a_msg_cst msg_cst;
    struct OpenChaoJi_gbt27930_a_msg_csd msg_csd;
    struct OpenChaoJi_gbt27930_a_msg_cem msg_cem;

    struct OpenChaoJi_gbt27930_a_msg_bhm msg_bhm;
    struct OpenChaoJi_gbt27930_a_msg_brm msg_brm;
    struct OpenChaoJi_gbt27930_a_msg_bcp msg_bcp;
    struct OpenChaoJi_gbt27930_a_msg_bro msg_bro;
    struct OpenChaoJi_gbt27930_a_msg_bcl msg_bcl;
    struct OpenChaoJi_gbt27930_a_msg_bcs msg_bcs;
    struct OpenChaoJi_gbt27930_a_msg_bsm msg_bsm;
    struct OpenChaoJi_gbt27930_a_msg_bmv msg_bmv;
    struct OpenChaoJi_gbt27930_a_msg_bmt msg_bmt;
    struct OpenChaoJi_gbt27930_a_msg_bsp msg_bsp;
    struct OpenChaoJi_gbt27930_a_msg_bst msg_bst;
    struct OpenChaoJi_gbt27930_a_msg_bsd msg_bsd;
    struct OpenChaoJi_gbt27930_a_msg_bem msg_bem;

    int msg_chm_ok;         // 接收到chm报文
    int msg_crm_ok;         // 接收到crm报文
    int msg_cro_ok;         // 接收到cro报文
    int msg_cts_ok;         // 接收到cts报文
    int msg_cml_ok;         // 接收到cml报文

    int msg_ccs_ok;         // 接收到ccs报文
    int msg_csd_ok;         // 接收到csd报文
    int msg_cst_ok;         // 接收到cst报文
    int msg_cem_ok;         // 接收到cem报文

    /* -------------- 日志专用 -------------- */
    struct {
        struct OpenChaoJi_gbt27930_a_msg_chm msg_chm;
        struct OpenChaoJi_gbt27930_a_msg_crm msg_crm;
        struct OpenChaoJi_gbt27930_a_msg_cts msg_cts;
        struct OpenChaoJi_gbt27930_a_msg_cml msg_cml;
        struct OpenChaoJi_gbt27930_a_msg_cro msg_cro;
        struct OpenChaoJi_gbt27930_a_msg_ccs msg_ccs;
        struct OpenChaoJi_gbt27930_a_msg_cst msg_cst;
        struct OpenChaoJi_gbt27930_a_msg_csd msg_csd;
        struct OpenChaoJi_gbt27930_a_msg_cem msg_cem;

        struct OpenChaoJi_gbt27930_a_msg_bhm msg_bhm;
        struct OpenChaoJi_gbt27930_a_msg_brm msg_brm;
        struct OpenChaoJi_gbt27930_a_msg_bcp msg_bcp;
        struct OpenChaoJi_gbt27930_a_msg_bro msg_bro;
        struct OpenChaoJi_gbt27930_a_msg_bcl msg_bcl;
        struct OpenChaoJi_gbt27930_a_msg_bcs msg_bcs;
        struct OpenChaoJi_gbt27930_a_msg_bsm msg_bsm;
        struct OpenChaoJi_gbt27930_a_msg_bmv msg_bmv;
        struct OpenChaoJi_gbt27930_a_msg_bmt msg_bmt;
        struct OpenChaoJi_gbt27930_a_msg_bsp msg_bsp;
        struct OpenChaoJi_gbt27930_a_msg_bst msg_bst;
        struct OpenChaoJi_gbt27930_a_msg_bsd msg_bsd;
        struct OpenChaoJi_gbt27930_a_msg_bem msg_bem;
   } log_msg;
};


/* 格式转换, BCD转HEX */
static uint8_t OpenChaoJi_gbt27930_a_evcc_bcd_to_hex(uint8_t bcd)
{
    return ((bcd & 0xF0) >> 4) * 10 + (bcd & 0x0F);
}

bool s_gbt_a_public_debug_enable = false;
void OpenChaoJi_debug_set_log_module_gbt_a_public(bool enable)
{
    s_gbt_a_public_debug_enable = enable;
}

/* -------------- Debug -------------- */

static int OpenChaoJi_gbt27930_a_evcc_parse_data(struct OpenChaoJi_evcc_context * context, struct OpenChaoJi_utility_data_buff_recv_data * recv_data);

static void OpenChaoJi_gbt27930_a_evcc_running_data_timer_reset(struct OpenChaoJi_evcc_context * context)
{
    LOG_NOTICE("[%d]STOP ALL TIMER", context->tag);

    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bhm);
    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_brm);
    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bcp);
    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bro);
    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bcl);
    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bcs);
    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bsm);
    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bmv);
    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bmt);
    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bsp);
    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bst);
    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bsd);
    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bem);

    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_chm);
    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_crm_00);
    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_crm_aa);
    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_cml);
    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_cts);
    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_cro);
    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_cro_aa);
    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_ccs);
    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_cst);
    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_csd);

    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_bslp);
    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_bep);
    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_crm);
    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_csup);
    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_stopping);

    return;
}

static void OpenChaoJi_gbt27930_a_evcc_running_data_reset(struct OpenChaoJi_evcc_context * context)
{
    LOG_STATUS_CHANGE("[%d]RESET RUNNING DATA", context->tag);

	memset(context->running_data.a, 0x00, sizeof(struct OpenChaoJi_evcc_gbt27930_a_data));
    // BST
    context->running_data.a->msg_bst.error_code.all = 0xC0;
    // BEM
    context->running_data.a->msg_bem.tout_code.all = 0xFCF0F0F0;
    // BHM
    context->running_data.a->msg_bhm.insul_request_voltage = OpenChaoJi_evcc_hal_get_imd_request_voltage(context->hal_handle);  // 车辆端绝缘监测允许总电压
    // BRM
    context->running_data.a->msg_brm.pro_version[0] = OPENCHAOJI_GBT27930_A_PROTOCOL_VERSION_TYPE_MAJOR(OPENCHAOJI_GBT27930_A_PROTOCOL_VERSION_TYPE_1_1_0); // 车辆通信协议版本号
    context->running_data.a->msg_brm.pro_version[1] = OPENCHAOJI_GBT27930_A_PROTOCOL_VERSION_TYPE_MINOR(OPENCHAOJI_GBT27930_A_PROTOCOL_VERSION_TYPE_1_1_0);
    context->running_data.a->msg_brm.pro_version[2] = OPENCHAOJI_GBT27930_A_PROTOCOL_VERSION_TYPE_TMP(OPENCHAOJI_GBT27930_A_PROTOCOL_VERSION_TYPE_1_1_0);
    context->running_data.a->msg_brm.sw_version[0] =  OPENCHAOJI_GBT27930_A_SOFTWARE_RELEASE_SN;                        // 软件版本流水号(第几次编译)
    context->running_data.a->msg_brm.sw_version[1] = (OPENCHAOJI_GBT27930_A_SOFTWARE_RELEASE_DATE >> 0) & 0xFF;         // 软件版本编译时间
    context->running_data.a->msg_brm.sw_version[2] = (OPENCHAOJI_GBT27930_A_SOFTWARE_RELEASE_DATE >> 8) & 0xFF;
    context->running_data.a->msg_brm.sw_version[3] = (OPENCHAOJI_GBT27930_A_SOFTWARE_RELEASE_DATE >> 24) & 0xFF;
    context->running_data.a->msg_brm.sw_version[4] = (OPENCHAOJI_GBT27930_A_SOFTWARE_RELEASE_DATE >> 16) & 0xFF;
    context->running_data.a->msg_brm.sw_version[5] = 0xFF;
    context->running_data.a->msg_brm.sw_version[6] = 0xFF;
    context->running_data.a->msg_brm.sw_version[7] = 0xFF;
    context->running_data.a->msg_brm.batt_type = OpenChaoJi_evcc_hal_get_batt_type(context->hal_handle);                // 电池类型
    context->running_data.a->msg_brm.rated_capacity = OpenChaoJi_evcc_hal_get_rated_capacity(context->hal_handle);      // 动力蓄电池额定容量
    context->running_data.a->msg_brm.rated_voltage = OpenChaoJi_evcc_hal_get_rated_voltage(context->hal_handle);        // 动力蓄电池额定总电压
    uint32_t charge_cycles;
	charge_cycles = OpenChaoJi_evcc_hal_get_charge_cycles(context->hal_handle);        		 // 电池组充电次数
	context->running_data.a->msg_brm.charge_cycles[0] = charge_cycles & 0xFF;       		 // 电池组充电次数
	context->running_data.a->msg_brm.charge_cycles[1] = (charge_cycles >> 8) & 0xFF;         // 电池组充电次数
	context->running_data.a->msg_brm.charge_cycles[2] = (charge_cycles >> 16) & 0xFF;        // 电池组充电次数
    context->running_data.a->msg_brm.batt_property = OpenChaoJi_evcc_hal_get_batt_property(context->hal_handle);        // 电池组产权标识
    context->running_data.a->msg_brm.res = 0xFF;
    struct OpenChaoJi_evcc_hal_batt_date date;
    date = OpenChaoJi_evcc_hal_get_batt_date(context->hal_handle);                                                      // 电池组生产日期
    context->running_data.a->msg_brm.batt_date_year = date.year - 1985;
    context->running_data.a->msg_brm.batt_date_month = date.month;
    context->running_data.a->msg_brm.batt_date_day = date.day;
    OpenChaoJi_evcc_hal_get_batt_factory(context->hal_handle, context->running_data.a->msg_brm.batt_factory);           // 电池生产厂商名称
    OpenChaoJi_evcc_hal_get_batt_sn(context->hal_handle, context->running_data.a->msg_brm.batt_sn);                     // 电池组序号
    OpenChaoJi_evcc_hal_get_evin(context->hal_handle, context->running_data.a->msg_brm.evin);                           // 扩展车辆识别码 (EVIN)
    // BCP
    context->running_data.a->msg_bcp.allow_cellvolt = OpenChaoJi_evcc_hal_get_allow_cellvolt(context->hal_handle);      // 单体蓄电池最高允许充电电压
    context->running_data.a->msg_bcp.allow_current = 4000 - OpenChaoJi_evcc_hal_get_allow_current(context->hal_handle); // 最高允许充电电流
    context->running_data.a->msg_bcp.rated_energy = OpenChaoJi_evcc_hal_get_rated_energy(context->hal_handle);          // 动力蓄电池标称总能量
    context->running_data.a->msg_bcp.allow_voltage = OpenChaoJi_evcc_hal_get_allow_voltage(context->hal_handle);        // 最高允许充电总电压
    context->running_data.a->msg_bcp.allow_tempera = 50 + OpenChaoJi_evcc_hal_get_allow_tempera(context->hal_handle);   // 单体蓄电池最高允许温度
    context->running_data.a->msg_bcp.batt_soc = OpenChaoJi_evcc_hal_get_batt_soc(context->hal_handle);                  // 整车荷电状态
    context->running_data.a->msg_bcp.measured_voltage = OpenChaoJi_evcc_hal_get_measured_voltage(context->hal_handle);  // 车辆接口当前电压测量值

    OpenChaoJi_gbt27930_a_evcc_running_data_timer_reset(context);

    return;
}

static void OpenChaoJi_gbt27930_a_evcc_reset_to_default(struct OpenChaoJi_evcc_context * context)
{
    LOG_STATUS_CHANGE("[%d] RESET TO DEFAULT", context->tag);

    OpenChaoJi_evcc_utility_session_reset(context->context_session);
    OpenChaoJi_evcc_utility_pilot_reset(context->context_pilot);

	OpenChaoJi_gbt27930_a_evcc_running_data_reset(context);
}

static bool OpenChaoJi_gbt27930_a_evcc_log_msg_set(struct OpenChaoJi_evcc_context * context, struct OpenChaoJi_gbt27930_a_msg * msg)
{
    switch (msg->pid)
    {
    case OPENCHAOJI_GBT27930_A_PGN_CHM:
        if (memcmp(&context->running_data.a->log_msg.msg_chm, &msg->msg.chm, sizeof(msg->msg.chm)) != 0)
        {
            memcpy(&context->running_data.a->log_msg.msg_chm, &msg->msg.chm, sizeof(msg->msg.chm));
            return true;
        }
        return false;

    case OPENCHAOJI_GBT27930_A_PGN_CRM:
        if (memcmp(&context->running_data.a->log_msg.msg_crm, &msg->msg.crm, sizeof(msg->msg.crm)) != 0)
        {
            memcpy(&context->running_data.a->log_msg.msg_crm, &msg->msg.crm, sizeof(msg->msg.crm));
            return true;
        }
        return false;

    case OPENCHAOJI_GBT27930_A_PGN_CTS:
        if (memcmp(&context->running_data.a->log_msg.msg_cts, &msg->msg.cts, sizeof(msg->msg.cts)) != 0)
        {
            memcpy(&context->running_data.a->log_msg.msg_cts, &msg->msg.cts, sizeof(msg->msg.cts));
            return true;
        }
        return false;

    case OPENCHAOJI_GBT27930_A_PGN_CML:
        if (memcmp(&context->running_data.a->log_msg.msg_cml, &msg->msg.cml, sizeof(msg->msg.cml)) != 0)
        {
            memcpy(&context->running_data.a->log_msg.msg_cml, &msg->msg.cml, sizeof(msg->msg.cml));
            return true;
        }
        return false;

    case OPENCHAOJI_GBT27930_A_PGN_CRO:
        if (memcmp(&context->running_data.a->log_msg.msg_cro, &msg->msg.cro, sizeof(msg->msg.cro)) != 0)
        {
            memcpy(&context->running_data.a->log_msg.msg_cro, &msg->msg.cro, sizeof(msg->msg.cro));
            return true;
        }
        return false;

    case OPENCHAOJI_GBT27930_A_PGN_CCS:
        if (memcmp(&context->running_data.a->log_msg.msg_ccs, &msg->msg.ccs, sizeof(msg->msg.ccs)) != 0)
        {
            memcpy(&context->running_data.a->log_msg.msg_ccs, &msg->msg.ccs, sizeof(msg->msg.ccs));
            return true;
        }
        return false;

    case OPENCHAOJI_GBT27930_A_PGN_CST:
        if (memcmp(&context->running_data.a->log_msg.msg_cst, &msg->msg.cst, sizeof(msg->msg.cst)) != 0)
        {
            memcpy(&context->running_data.a->log_msg.msg_cst, &msg->msg.cst, sizeof(msg->msg.cst));
            return true;
        }
        return false;

    case OPENCHAOJI_GBT27930_A_PGN_CSD:
        if (memcmp(&context->running_data.a->log_msg.msg_csd, &msg->msg.csd, sizeof(msg->msg.csd)) != 0)
        {
            memcpy(&context->running_data.a->log_msg.msg_csd, &msg->msg.csd, sizeof(msg->msg.csd));
            return true;
        }
        return false;

    case OPENCHAOJI_GBT27930_A_PGN_CEM:
        if (memcmp(&context->running_data.a->log_msg.msg_cem, &msg->msg.cem, sizeof(msg->msg.cem)) != 0)
        {
            memcpy(&context->running_data.a->log_msg.msg_cem, &msg->msg.cem, sizeof(msg->msg.cem));
            return true;
        }
        return false;

    case OPENCHAOJI_GBT27930_A_PGN_BHM:
        if (memcmp(&context->running_data.a->log_msg.msg_bhm, &msg->msg.bhm, sizeof(msg->msg.bhm)) != 0)
        {
            memcpy(&context->running_data.a->log_msg.msg_bhm, &msg->msg.bhm, sizeof(msg->msg.bhm));
            return true;
        }
        return false;

    case OPENCHAOJI_GBT27930_A_PGN_BRM:
        if (memcmp(&context->running_data.a->log_msg.msg_brm, &msg->msg.brm, sizeof(msg->msg.brm)) != 0)
        {
            memcpy(&context->running_data.a->log_msg.msg_brm, &msg->msg.brm, sizeof(msg->msg.brm));
            return true;
        }
        return false;

    case OPENCHAOJI_GBT27930_A_PGN_BCP:
        if (memcmp(&context->running_data.a->log_msg.msg_bcp, &msg->msg.bcp, sizeof(msg->msg.bcp)) != 0)
        {
            memcpy(&context->running_data.a->log_msg.msg_bcp, &msg->msg.bcp, sizeof(msg->msg.bcp));
            return true;
        }
        return false;

    case OPENCHAOJI_GBT27930_A_PGN_BRO:
        if (memcmp(&context->running_data.a->log_msg.msg_bro, &msg->msg.bro, sizeof(msg->msg.bro)) != 0)
        {
            memcpy(&context->running_data.a->log_msg.msg_bro, &msg->msg.bro, sizeof(msg->msg.bro));
            return true;
        }
        return false;

    case OPENCHAOJI_GBT27930_A_PGN_BCL:
        if (memcmp(&context->running_data.a->log_msg.msg_bcl, &msg->msg.bcl, sizeof(msg->msg.bcl)) != 0)
        {
            memcpy(&context->running_data.a->log_msg.msg_bcl, &msg->msg.bcl, sizeof(msg->msg.bcl));
            return true;
        }
        return false;

    case OPENCHAOJI_GBT27930_A_PGN_BCS:
        if (memcmp(&context->running_data.a->log_msg.msg_bcs, &msg->msg.bcs, sizeof(msg->msg.bcs)) != 0)
        {
            memcpy(&context->running_data.a->log_msg.msg_bcs, &msg->msg.bcs, sizeof(msg->msg.bcs));
            return true;
        }
        return false;

    case OPENCHAOJI_GBT27930_A_PGN_BSM:
        if (memcmp(&context->running_data.a->log_msg.msg_bsm, &msg->msg.bsm, sizeof(msg->msg.bsm)) != 0)
        {
            memcpy(&context->running_data.a->log_msg.msg_bsm, &msg->msg.bsm, sizeof(msg->msg.bsm));
            return true;
        }
        return false;

    case OPENCHAOJI_GBT27930_A_PGN_BMV:
        if (memcmp(&context->running_data.a->log_msg.msg_bmv, &msg->msg.bmv, sizeof(msg->msg.bmv)) != 0)
        {
            memcpy(&context->running_data.a->log_msg.msg_bmv, &msg->msg.bmv, sizeof(msg->msg.bmv));
            return true;
        }
        return false;

    case OPENCHAOJI_GBT27930_A_PGN_BMT:
        if (memcmp(&context->running_data.a->log_msg.msg_bmt, &msg->msg.bmt, sizeof(msg->msg.bmt)) != 0)
        {
            memcpy(&context->running_data.a->log_msg.msg_bmt, &msg->msg.bmt, sizeof(msg->msg.bmt));
            return true;
        }
        return false;

    case OPENCHAOJI_GBT27930_A_PGN_BSP:
        if (memcmp(&context->running_data.a->log_msg.msg_bsp, &msg->msg.bsp, sizeof(msg->msg.bsp)) != 0)
        {
            memcpy(&context->running_data.a->log_msg.msg_bsp, &msg->msg.bsp, sizeof(msg->msg.bsp));
            return true;
        }
        return false;

    case OPENCHAOJI_GBT27930_A_PGN_BST:
        if (memcmp(&context->running_data.a->log_msg.msg_bst, &msg->msg.bst, sizeof(msg->msg.bst)) != 0)
        {
            memcpy(&context->running_data.a->log_msg.msg_bst, &msg->msg.bst, sizeof(msg->msg.bst));
            return true;
        }
        return false;

    case OPENCHAOJI_GBT27930_A_PGN_BSD:
        if (memcmp(&context->running_data.a->log_msg.msg_bsd, &msg->msg.bsd, sizeof(msg->msg.bsd)) != 0)
        {
            memcpy(&context->running_data.a->log_msg.msg_bsd, &msg->msg.bsd, sizeof(msg->msg.bsd));
            return true;
        }
        return false;

    case OPENCHAOJI_GBT27930_A_PGN_BEM:
        if (memcmp(&context->running_data.a->log_msg.msg_bem, &msg->msg.bem, sizeof(msg->msg.bem)) != 0)
        {
            memcpy(&context->running_data.a->log_msg.msg_bem, &msg->msg.bem, sizeof(msg->msg.bem));
            return true;
        }
        return false;

    default: return false;
    }
}

// 通用报文发送
static int OpenChaoJi_gbt27930_a_evcc_send_normal(struct OpenChaoJi_evcc_context * context, uint32_t all, uint8_t *data ,uint16_t data_len)       // 数据发送
{
    struct OpenChaoJi_utility_data_buff_send_data send_data;
    send_data.tag.all = all;
    send_data.cnt = SEND_NORMAL_CNT_MACRO;
    send_data.interval_ms = SEND_NORMAL_INTERVAL_MS_MACRO;

    struct OpenChaoJi_gbt27930_a_msg msg;
    msg.pid = send_data.tag.gbt.pf;
    memcpy(&msg.msg, data, data_len);

 #if 0
    send_data.send_data.src_free = SEND_NORMAL_SRC_FREE_MACRO;
    send_data.send_data.data = data;
    send_data.send_data.len = data_len;
#else
    int dynamic_data_len = 0;
    unsigned char * dynamic_data = OpenChaoJi_gbt27930_a_msg_encode_data(&msg, &dynamic_data_len);
    if (dynamic_data == NULL)
    {
        return 0;
    }
    send_data.send_data.src_free = 0;
    send_data.send_data.data = dynamic_data;
    send_data.send_data.len = dynamic_data_len;
#endif

    bool changed = OpenChaoJi_gbt27930_a_evcc_log_msg_set(context, &msg);

    // 发送数据发生变化必须打出完整报文, 打印级别是INFO则把所有报文打印出来
    if ((changed) || ((OpenChaoJi_debug_get_log_level() & DBGL_INFO) != 0))
    {
        // 周期性报文, 即使INFO级别也不打印, 只变化才打印
        if (!changed && !s_gbt_a_public_debug_enable)
        {
            goto SEND_DATA;
        }

        OpenChaoJi_gbt27930_a_msg_log(&msg);
        if ((OpenChaoJi_debug_get_log_level() & DBGL_INFO) != 0)
        {
            LOG_DATA_CHANGE("->[%02X][%d]", msg.pid, send_data.send_data.len);
            LOG_DATA_BUFF_CHANGE(send_data.send_data.data, send_data.send_data.len);
        }
    }

SEND_DATA:
    return OpenChaoJi_evcc_utility_session_data_write(context->context_session, &send_data);
}

/* 停机中 */
enum OpenChaoJi_gbt27930_a_evcc_stopping_stauts {
    OPENCHAOJI_GBT27930_A_EVCC_STOPPING_STATUS_INIT = 0,            // 初始化
    OPENCHAOJI_GBT27930_A_EVCC_STOPPING_STATUS_REDUCE_CURRENT,      // 等待模块关机(降电流)
    OPENCHAOJI_GBT27930_A_EVCC_STOPPING_STATUS_CUT_OFF_C5_C6,       // 断开C5 C6
    OPENCHAOJI_GBT27930_A_EVCC_STOPPING_STATUS_FINISHED,            // 停机完成
    OPENCHAOJI_GBT27930_A_EVCC_STOPPING_STATUS_ERROR                // 停机故障
};

// 停机中
static int OpenChaoJi_gbt27930_a_evcc_stopping(struct OpenChaoJi_evcc_context * context)
{
    struct OpenChaoJi_evcc_hal_samp samp_value;
    if (context->running_data.a->stop_status == OPENCHAOJI_GBT27930_A_EVCC_STOPPING_STATUS_INIT)
    {
        // 开启停机超时定时器, 超时时间由外部传入 stop_ticks
        LOG_INFO("[%d]stopping: start current timer", context->tag);
        OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvo_stopping, context->running_data.a->stop_ticks);
        context->running_data.a->stop_status = OPENCHAOJI_GBT27930_A_EVCC_STOPPING_STATUS_REDUCE_CURRENT;
    }
    else if (context->running_data.a->stop_status == OPENCHAOJI_GBT27930_A_EVCC_STOPPING_STATUS_REDUCE_CURRENT)
    {
        OpenChaoJi_evcc_hal_sampling_value(context->hal_handle, &samp_value);
        LOG_DEBUG("[%d]stopping: current=%d", context->tag, samp_value.current);
        //电流降至5A及以下
        if (samp_value.current <= 50 || OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvo_stopping))
        {
            LOG_NOTICE("[%d]stopping: cut off C5 C6", context->tag);
            OpenChaoJi_evcc_hal_gbt_close_dc_relay(context->hal_handle, 0); // 断开C5 C6
            // 启动定时器, 用于C5 C6断开动作超时检测
            LOG_INFO("[%d]stopping: start C5 C6 timer", context->tag);
            OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvo_stopping, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVO_RELAY);
            context->running_data.a->stop_status = OPENCHAOJI_GBT27930_A_EVCC_STOPPING_STATUS_CUT_OFF_C5_C6;
        }
    }
    else if (context->running_data.a->stop_status == OPENCHAOJI_GBT27930_A_EVCC_STOPPING_STATUS_CUT_OFF_C5_C6)
    {
        // 等待C5C6断开
        if (OpenChaoJi_evcc_hal_get_status_dc_relay(context->hal_handle) == 0)
        {
            LOG_NOTICE("[%d]stopping: C5 C6 already cut off, evcc stopped", context->tag);
            context->running_data.a->stop_status = OPENCHAOJI_GBT27930_A_EVCC_STOPPING_STATUS_FINISHED;
        }
        else
        {
            LOG_DEBUG("[%d]stopping: cut off C5 C6 (again)", context->tag);
            OpenChaoJi_evcc_hal_gbt_close_dc_relay(context->hal_handle, 0); // 断开C5 C6
            // C5 C6断开超时判断
            if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvo_stopping))
            {
                // C5 C6断开超时, 故障
                LOG_ERR("[%d]stopping: cut off C5 C6 failed", context->tag);
                context->running_data.a->stop_status = OPENCHAOJI_GBT27930_A_EVCC_STOPPING_STATUS_ERROR;
            }
        }
    }
    return context->running_data.a->stop_status;
}

static int OpenChaoJi_gbt27930_a_evcc_stop_normal(struct OpenChaoJi_evcc_context * context, uint8_t end_code, uint8_t end_reason) // 正常停机
{
    LOG_NOTICE("[%d]NormalStopCharge: code=%02x, reason=%02x", context->tag, end_code, end_reason);

    // 解析停机代码 // TODO: 故障码定义、BST映射
    if (end_code == OPENCHAOJI_GBT27930_A_END_CODE_EVCC_NORMAL)
    {
        switch (end_reason)
        {
            case OPENCHAOJI_GBT27930_A_END_REASON_EVCC_NORMAL_SOC:
                context->running_data.a->msg_bst.stop_code.bits.soc = 0x01;         // 达到所需求的SOC目标值
                break;
            case OPENCHAOJI_GBT27930_A_END_REASON_EVCC_NORMAL_VOLTAGE:
                context->running_data.a->msg_bst.stop_code.bits.voltage = 0x01;     // 达到总电压的设定值
                break;
            case OPENCHAOJI_GBT27930_A_END_REASON_EVCC_NORMAL_CELL_VOLTAGE:
                context->running_data.a->msg_bst.stop_code.bits.cellvolt = 0x01;    // 达到单体电压的设定值
                break;
            case OPENCHAOJI_GBT27930_A_END_REASON_EVCC_NORMAL_CST:
                context->running_data.a->msg_bst.stop_code.bits.charger = 0x01;     // 充电机主动中止
                break;
            default:
                context->running_data.a->msg_bst.fault_code.bits.other = 0x01;      // 其他故障
                break;
        }
    }
    else // 停机码异常, 非正常停机
    {
        context->running_data.a->msg_bst.fault_code.bits.other = 0x01;    // 其他故障
    }

    if (end_reason == OPENCHAOJI_GBT27930_A_END_REASON_EVCC_NORMAL_CST)
    {
        // 充电机主动停止, 进入停机结束阶段
        LOG_NOTICE("[%d]NormalStopCharge To Charge S6", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S6_SE_STOP;
    }
    else
    {
        // 车辆主动停止, 等待充电机进入停机阶段
        LOG_NOTICE("[%d]NormalStopCharge To Charge S5", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S5_EV_STOP;
    }
}

static int OpenChaoJi_gbt27930_a_evcc_stop_failed(struct OpenChaoJi_evcc_context * context, uint8_t end_code, uint8_t end_reason) // 故障停机
{
    context->running_data.a->end_code = end_code;
    LOG_ERR("[%d]ErrStopCharge: code=%02x, reason=%02x", context->tag, end_code, end_reason);

    // 解析停机代码 // TODO: 故障码定义、BST映射
    if (end_code == OPENCHAOJI_GBT27930_A_END_CODE_EVCC_FAULT)
    {
        switch (end_reason)
        {
            case OPENCHAOJI_GBT27930_A_END_REASON_EVCC_FAULT_CC2_VOLTAGE:
                context->running_data.a->msg_bst.fault_code.bits.cc2_volt = 0x01;   // 检测点2电压检测故障
                break;
            case OPENCHAOJI_GBT27930_A_END_REASON_EVCC_FAULT_COUPLER:
                context->running_data.a->msg_bst.fault_code.bits.coupler = 0x01;    // 充电耦合器连接故障
                break;
            case OPENCHAOJI_GBT27930_A_END_REASON_EVCC_FAULT_OTHER:
                context->running_data.a->msg_bst.fault_code.bits.other = 0x01;      // 其他故障
                break;
            default:
                context->running_data.a->msg_bst.fault_code.bits.other = 0x01;      // 其他故障
                break;
        }
    }
    else if (end_code == OPENCHAOJI_GBT27930_A_END_CODE_EVCC_ERROR)
    {
        switch (end_reason)
        {
            case OPENCHAOJI_GBT27930_A_END_REASON_EVCC_ERROR_VOLTAGE:
                context->running_data.a->msg_bst.error_code.bits.voltage = 0x01;    // 电压异常
                break;
            case OPENCHAOJI_GBT27930_A_END_REASON_EVCC_ERROR_CURRENT:
                context->running_data.a->msg_bst.error_code.bits.current = 0x01;    // 电流不匹配
                break;
            case OPENCHAOJI_GBT27930_A_END_REASON_EVCC_ERROR_PARAM:
                context->running_data.a->msg_bst.error_code.bits.param = 0x01;      // 充电参数不匹配
                break;
            default:
                context->running_data.a->msg_bst.fault_code.bits.other = 0x01;      // 其他故障
                break;
        }
    }
    else // 停机码异常, 非正常停机
    {
        context->running_data.a->msg_bst.fault_code.bits.other = 0x01;    // 其他故障
    }

    // 车辆主动停止, 等待充电机进入停机阶段
    LOG_ERR("[%d]ErrStopCharge To Charge S5", context->tag);
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S5_EV_STOP;
}

// static int OpenChaoJi_gbt27930_a_evcc_stop_emergency(struct OpenChaoJi_evcc_context * context, uint8_t end_code, uint8_t end_reason) // 紧急停机
// {
//     return 0;
// }

static int OpenChaoJi_gbt27930_a_evcc_rcvd_cem(struct OpenChaoJi_evcc_context * context) // 接收到充电机CEM报文
{
    // 进入超时处理阶段
    LOG_ERR("[%d]CEM To Error S0", context->tag);
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_ERROR_S0_INIT;
}

/* idle */
static void OpenChaoJi_gbt27930_a_evcc_prev_idle_s0_idle(struct OpenChaoJi_evcc_context * context)
{
    OpenChaoJi_gbt27930_a_evcc_reset_to_default(context);
}
static void OpenChaoJi_gbt27930_a_evcc_post_idle_s0_idle(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_idle_s0_idle(struct OpenChaoJi_evcc_context * context)
{
    if (context->app_permit_charge)
    {
        LOG_NOTICE("[%d]Idle S0, app permit charge", context->tag);
        // 数据缓存初始化
        // memset(context->running_data.a, 0, sizeof(struct OpenChaoJi_evcc_gbt27930_a_data));
        LOG_NOTICE("[%d]Idle S0 To Trigger S0", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_TRIGGER_S0_CONNECT_CONFIRM;
    }

    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_IDLE_S0_IDLE;
}

const struct OpenChaoJi_evcc_module_status c_sytem_a_evcc_status_array_idle[OPENCHAOJI_GBT27930_A_EVCC_STATUS_IDLE_NUM] = {
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_IDLE_S0_IDLE,
        .name = "Idle.S0.Idle",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_idle_s0_idle,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_idle_s0_idle,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_idle_s0_idle,
    },
};

const struct OpenChaoJi_evcc_module c_gbt27930_a_evcc_module_idle =
{
    .module_id = OPENCHAOJI_GBT27930_A_MODULE_IDLE,
    .name = "Idle",
    .status_array = c_sytem_a_evcc_status_array_idle,
    .status_array_len = OPENCHAOJI_GBT27930_A_EVCC_STATUS_IDLE_NUM,
};

/* trigger */
static void OpenChaoJi_gbt27930_a_evcc_prev_trigger_s0_connect_confirm(struct OpenChaoJi_evcc_context * context) {}
static void OpenChaoJi_gbt27930_a_evcc_post_trigger_s0_connect_confirm(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_trigger_s0_connect_confirm(struct OpenChaoJi_evcc_context * context)
{
    if (OpenChaoJi_evcc_utility_pilot_is_secc_connected(context->context_pilot))   // 18487.B.4.1, 连接（唤醒）
    {
        LOG_NOTICE("[%d]Trigger S0 To S1", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_TRIGGER_S1_AUX_CONFIRM;
    }

    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_TRIGGER_S0_CONNECT_CONFIRM;
}

static void OpenChaoJi_gbt27930_a_evcc_prev_trigger_s1_aux_confirm(struct OpenChaoJi_evcc_context * context) {}
static void OpenChaoJi_gbt27930_a_evcc_post_trigger_s1_aux_confirm(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_trigger_s1_aux_confirm(struct OpenChaoJi_evcc_context * context)
{
    if (OpenChaoJi_evcc_hal_gbt_a_is_secc_aux_connected(context->hal_handle))   // 辅源状态
    {
        LOG_NOTICE("[%d]Trigger S1 To Handshake S0", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_HANDSHAKE_S0_INIT;
    }

    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_TRIGGER_S1_AUX_CONFIRM;
}

const struct OpenChaoJi_evcc_module_status c_sytem_a_evcc_status_array_trigger[OPENCHAOJI_GBT27930_A_EVCC_STATUS_TRIGGER_NUM] = {
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_TRIGGER_S0_CONNECT_CONFIRM,
        .name = "Trigger.S0.Connect.Confirm",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_trigger_s0_connect_confirm,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_trigger_s0_connect_confirm,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_trigger_s0_connect_confirm,
    },
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_TRIGGER_S1_AUX_CONFIRM,
        .name = "Trigger.S1.Aux.Confirm",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_trigger_s1_aux_confirm,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_trigger_s1_aux_confirm,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_trigger_s1_aux_confirm,
    },
};

const struct OpenChaoJi_evcc_module c_gbt27930_a_evcc_module_trigger =
{
    .module_id = OPENCHAOJI_GBT27930_A_MODULE_TRIGGER,
    .name = "Trigger",
    .status_array = c_sytem_a_evcc_status_array_trigger,
    .status_array_len = OPENCHAOJI_GBT27930_A_EVCC_STATUS_TRIGGER_NUM,
};

/* 充电握手 */

static void OpenChaoJi_gbt27930_a_evcc_prev_handshake_s0_init(struct OpenChaoJi_evcc_context * context)
{
    LOG_NOTICE("[%d]Handshake Status Start", context->tag);
    LOG_NOTICE("[%d]Handshake S0 init", context->tag);
    // 初始化
    context->running_data.a->protocol_version = OPENCHAOJI_GBT27930_A_PROTOCOL_VERSION_TYPE_MAKE(1,1,0);
    context->running_data.a->stop_status = OPENCHAOJI_GBT27930_A_EVCC_STOPPING_STATUS_INIT;
    context->running_data.a->stop_ticks = OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVO_STOP_NORMAL(0);
    context->running_data.a->msg_cem_ok = 0;
    // BST
    memset(&context->running_data.a->msg_bst, 0, sizeof(struct OpenChaoJi_gbt27930_a_msg_bst));
    context->running_data.a->msg_bst.error_code.all = 0xC0;
    // BEM
    memset(&context->running_data.a->msg_bem, 0, sizeof(struct OpenChaoJi_gbt27930_a_msg_bem));
    context->running_data.a->msg_bem.tout_code.all = 0xFCF0F0F0;
    // BHM
    context->running_data.a->msg_bhm.insul_request_voltage = OpenChaoJi_evcc_hal_get_imd_request_voltage(context->hal_handle);  // 车辆端绝缘监测允许总电压
    // BRM
    context->running_data.a->msg_brm.pro_version[0] = OPENCHAOJI_GBT27930_A_PROTOCOL_VERSION_TYPE_MAJOR(OPENCHAOJI_GBT27930_A_PROTOCOL_VERSION_TYPE_1_1_0); // 车辆通信协议版本号
    context->running_data.a->msg_brm.pro_version[1] = OPENCHAOJI_GBT27930_A_PROTOCOL_VERSION_TYPE_MINOR(OPENCHAOJI_GBT27930_A_PROTOCOL_VERSION_TYPE_1_1_0);
    context->running_data.a->msg_brm.pro_version[2] = OPENCHAOJI_GBT27930_A_PROTOCOL_VERSION_TYPE_TMP(OPENCHAOJI_GBT27930_A_PROTOCOL_VERSION_TYPE_1_1_0);
    context->running_data.a->msg_brm.sw_version[0] =  OPENCHAOJI_GBT27930_A_SOFTWARE_RELEASE_SN;                        // 软件版本流水号(第几次编译)
    context->running_data.a->msg_brm.sw_version[1] = (OPENCHAOJI_GBT27930_A_SOFTWARE_RELEASE_DATE >> 0) & 0xFF;         // 软件版本编译时间
    context->running_data.a->msg_brm.sw_version[2] = (OPENCHAOJI_GBT27930_A_SOFTWARE_RELEASE_DATE >> 8) & 0xFF;
    context->running_data.a->msg_brm.sw_version[3] = (OPENCHAOJI_GBT27930_A_SOFTWARE_RELEASE_DATE >> 24) & 0xFF;
    context->running_data.a->msg_brm.sw_version[4] = (OPENCHAOJI_GBT27930_A_SOFTWARE_RELEASE_DATE >> 16) & 0xFF;
    context->running_data.a->msg_brm.sw_version[5] = 0xFF;
    context->running_data.a->msg_brm.sw_version[6] = 0xFF;
    context->running_data.a->msg_brm.sw_version[7] = 0xFF;
    context->running_data.a->msg_brm.batt_type = OpenChaoJi_evcc_hal_get_batt_type(context->hal_handle);                // 电池类型
    context->running_data.a->msg_brm.rated_capacity = OpenChaoJi_evcc_hal_get_rated_capacity(context->hal_handle);      // 动力蓄电池额定容量
    context->running_data.a->msg_brm.rated_voltage = OpenChaoJi_evcc_hal_get_rated_voltage(context->hal_handle);        // 动力蓄电池额定总电压
    uint32_t charge_cycles;
	charge_cycles = OpenChaoJi_evcc_hal_get_charge_cycles(context->hal_handle);        		 // 电池组充电次数
	context->running_data.a->msg_brm.charge_cycles[0] = charge_cycles & 0xFF;       		 // 电池组充电次数
	context->running_data.a->msg_brm.charge_cycles[1] = (charge_cycles >> 8) & 0xFF;         // 电池组充电次数
	context->running_data.a->msg_brm.charge_cycles[2] = (charge_cycles >> 16) & 0xFF;        // 电池组充电次数
    context->running_data.a->msg_brm.batt_property = OpenChaoJi_evcc_hal_get_batt_property(context->hal_handle);        // 电池组产权标识
    context->running_data.a->msg_brm.res = 0xFF;
    struct OpenChaoJi_evcc_hal_batt_date date;
    date = OpenChaoJi_evcc_hal_get_batt_date(context->hal_handle);                                                      // 电池组生产日期
    context->running_data.a->msg_brm.batt_date_year = date.year - 1985;
    context->running_data.a->msg_brm.batt_date_month = date.month;
    context->running_data.a->msg_brm.batt_date_day = date.day;
    OpenChaoJi_evcc_hal_get_batt_factory(context->hal_handle, context->running_data.a->msg_brm.batt_factory);           // 电池生产厂商名称
    OpenChaoJi_evcc_hal_get_batt_sn(context->hal_handle, context->running_data.a->msg_brm.batt_sn);                     // 电池组序号
    OpenChaoJi_evcc_hal_get_evin(context->hal_handle, context->running_data.a->msg_brm.evin);                           // 扩展车辆识别码 (EVIN)
    // BCP
    context->running_data.a->msg_bcp.allow_cellvolt = OpenChaoJi_evcc_hal_get_allow_cellvolt(context->hal_handle);      // 单体蓄电池最高允许充电电压
    context->running_data.a->msg_bcp.allow_current = 4000 - OpenChaoJi_evcc_hal_get_allow_current(context->hal_handle); // 最高允许充电电流
    context->running_data.a->msg_bcp.rated_energy = OpenChaoJi_evcc_hal_get_rated_energy(context->hal_handle);          // 动力蓄电池标称总能量
    context->running_data.a->msg_bcp.allow_voltage = OpenChaoJi_evcc_hal_get_allow_voltage(context->hal_handle);        // 最高允许充电总电压
    context->running_data.a->msg_bcp.allow_tempera = 50 + OpenChaoJi_evcc_hal_get_allow_tempera(context->hal_handle);   // 单体蓄电池最高允许温度
    context->running_data.a->msg_bcp.batt_soc = OpenChaoJi_evcc_hal_get_batt_soc(context->hal_handle);                  // 整车荷电状态
    context->running_data.a->msg_bcp.measured_voltage = OpenChaoJi_evcc_hal_get_measured_voltage(context->hal_handle);  // 车辆接口当前电压测量值
}
static void OpenChaoJi_gbt27930_a_evcc_post_handshake_s0_init(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_handshake_s0_init(struct OpenChaoJi_evcc_context * context)
{
    if (!context->running_data.a->reconnect_flag) // 首次通信连接
    {
        LOG_NOTICE("[%d]Handshake S0 communicate start", context->tag);

        // 打开TVObslp
        LOG_INFO("[%d]Handshake S0 start timer TVObslp", context->tag);
        OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvo_bslp, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVOBSLP);

        // 进入S1
        LOG_NOTICE("[%d]Handshake S0 To S1", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_HANDSHAKE_S1_CONNECT;
    }
    else //if (context->running_data.a->reconnect_flag) // 通信重连, 已收到CRM报文
    {
        LOG_NOTICE("[%d]Handshake S0 reconnect", context->tag);

        // 发送BRM报文
        LOG_INFO("[%d]Handshake S0 send brm", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BRM, (uint8_t *)(&context->running_data.a->msg_brm), sizeof(context->running_data.a->msg_brm));

        // 打开TVPbrm
        LOG_INFO("[%d]Handshake S0 start timer TVPbrm", context->tag);
        OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvp_brm, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVPBRM);

        // 打开TVOcrmAA
        LOG_INFO("[%d]Handshake S0 start timer TVOcrmAA", context->tag);
        OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvo_crm_aa, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVOCRM_AA);

        // 进入S4
        LOG_NOTICE("[%d]Handshake S0 To S4", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_HANDSHAKE_S4_RECOGINZE;
    }
}

static void OpenChaoJi_gbt27930_a_evcc_prev_handshake_s1_connect(struct OpenChaoJi_evcc_context * context) {}
static void OpenChaoJi_gbt27930_a_evcc_post_handshake_s1_connect(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_handshake_s1_connect(struct OpenChaoJi_evcc_context * context)
{
    // 车辆接口连接确认
    if (OpenChaoJi_evcc_utility_pilot_is_secc_connected(context->context_pilot))
    {
        LOG_NOTICE("[%d]Handshake S1 evcc pilot is connected", context->tag);
        // 进入S2
        LOG_NOTICE("[%d]Handshake S1 To S2", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_HANDSHAKE_S2_WAIT_NEGO;
    }

    // TVObslp定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvo_bslp))
    {
        LOG_ERR("[%d]Handshake S1 TVObslp timeout", context->tag);
        // 进入S7
        LOG_ERR("[%d]Handshake S1 To S7", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_HANDSHAKE_S7_FINISHED;
    }

    // 未确认, 未超时, 继续等待
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_HANDSHAKE_S1_CONNECT;
}

static void OpenChaoJi_gbt27930_a_evcc_prev_handshake_s2_wait_nego(struct OpenChaoJi_evcc_context * context)
{
    context->running_data.a->msg_chm_ok = 0;
    context->running_data.a->msg_crm_ok = 0;
}
static void OpenChaoJi_gbt27930_a_evcc_post_handshake_s2_wait_nego(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_handshake_s2_wait_nego(struct OpenChaoJi_evcc_context * context)
{
    // 接收充电机CHM报文
    if (context->running_data.a->msg_chm_ok)
    {
        LOG_NOTICE("[%d]Handshake S2 chm received", context->tag);

        // 关闭TVObslp
        LOG_INFO("[%d]Handshake S2 stop timer TVObslp", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_bslp);

        // 发送BHM报文
        LOG_INFO("[%d]Handshake S2 send bhm", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BHM, (uint8_t *)(&context->running_data.a->msg_bhm), sizeof(context->running_data.a->msg_bhm));

        // 打开TVPbhm
        LOG_INFO("[%d]Handshake S2 start timer TVPbhm", context->tag);
        OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvp_bhm, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVPBHM);

        // 打开TVOcrm00
        LOG_INFO("[%d]Handshake S2 start timer TVOcrm00", context->tag);
        OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvo_crm_00, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVOCRM_00);

        // 进入S3
        LOG_NOTICE("[%d]Handshake S2 To S3", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_HANDSHAKE_S3_NEGO;
    }

    // 接收充电机CRM_00报文
    if (context->running_data.a->msg_crm_ok && \
        context->running_data.a->msg_crm.recognition_result == OPENCHAOJI_GBT27930_A_RECOGNIZE_TYPE_NOT_RECOGNIZED)
    {
        LOG_NOTICE("[%d]Handshake S2 crm_00 received", context->tag);

        //协议版本V1.0
        context->running_data.a->protocol_version = OPENCHAOJI_GBT27930_A_PROTOCOL_VERSION_TYPE_MAKE(1,0,0);

        // 关闭TVObslp
        LOG_INFO("[%d]Handshake S2 stop timer TVObslp", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_bslp);

        // 发送BRM报文
        LOG_INFO("[%d]Handshake S2 send brm", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BRM, (uint8_t *)(&context->running_data.a->msg_brm), sizeof(context->running_data.a->msg_brm));

        // 打开TVPbrm
        LOG_INFO("[%d]Handshake S2 start timer TVPbrm", context->tag);
        OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvp_brm, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVPBRM);

        // 打开TVOcrmAA
        LOG_INFO("[%d]Handshake S2 start timer TVOcrmAA", context->tag);
        OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvo_crm_aa, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVOCRM_AA);

        // 进入S4
        LOG_NOTICE("[%d]Handshake S2 To S4", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_HANDSHAKE_S4_RECOGINZE;
    }

    // TVObslp定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvo_bslp))
    {
        LOG_ERR("[%d]Handshake S2 TVObslp timeout", context->tag);
        // 进入S7
        LOG_ERR("[%d]Handshake S2 To S7", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_HANDSHAKE_S7_FINISHED;
    }

    // 未收到, 未超时, 继续等待
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_HANDSHAKE_S2_WAIT_NEGO;
}

static void OpenChaoJi_gbt27930_a_evcc_prev_handshake_s3_nego(struct OpenChaoJi_evcc_context * context)
{
    context->running_data.a->msg_crm_ok = 0;
}
static void OpenChaoJi_gbt27930_a_evcc_post_handshake_s3_nego(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_handshake_s3_nego(struct OpenChaoJi_evcc_context * context)
{
    // TVPbhm定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvp_bhm))
    {
        // 发送BHM报文
        LOG_INFO("[%d]Handshake S3 send bhm", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BHM, (uint8_t *)(&context->running_data.a->msg_bhm), sizeof(context->running_data.a->msg_bhm));

        // 重置TVPbhm
        LOG_INFO("[%d]Handshake S3 reset timer TVPbhm", context->tag);
        OpenChaoJi_os_soft_timer_reset(&context->running_data.a->tvp_bhm);
    }

    // 接收充电机CRM_00报文
    if (context->running_data.a->msg_crm_ok && \
        context->running_data.a->msg_crm.recognition_result == OPENCHAOJI_GBT27930_A_RECOGNIZE_TYPE_NOT_RECOGNIZED)
    {
        LOG_NOTICE("[%d]Handshake S3 crm_00 received", context->tag);

        // 关闭TVPbhm
        LOG_INFO("[%d]Handshake S3 stop timer TVPbhm", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bhm);

        // 关闭TVOcrm00
        LOG_INFO("[%d]Handshake S3 stop timer TVOcrm00", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_crm_00);

        // 发送BRM报文
        LOG_INFO("[%d]Handshake S3 send brm", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BRM, (uint8_t *)(&context->running_data.a->msg_brm), sizeof(context->running_data.a->msg_brm));

        // 打开TVPbrm
        LOG_INFO("[%d]Handshake S3 start timer TVPbrm", context->tag);
        OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvp_brm, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVPBRM);

        // 打开TVOcrmAA
        LOG_INFO("[%d]Handshake S3 start timer TVOcrmAA", context->tag);
        OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvo_crm_aa, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVOCRM_AA);

        // 进入S4
        LOG_NOTICE("[%d]Handshake S3 To S4", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_HANDSHAKE_S4_RECOGINZE;
    }

    // TVOcrm00定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvo_crm_00))
    {
        LOG_ERR("[%d]Handshake S3 crm_00 timeout", context->tag);

        // 关闭TVPbhm
        LOG_INFO("[%d]Handshake S3 stop timer TVPbhm", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bhm);

        // 发送BEM报文, 此处只更新错误代码, 进入错误处理阶段后执行发送
        context->running_data.a->msg_bem.tout_code.bits.crm_00 = 0x01; // CRM_00超时

        // 进入S6
        LOG_ERR("[%d]Handshake S3 To S6", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_HANDSHAKE_S6_ERROR;
    }

    // 未收到, 未超时, 继续等待, 保持S3
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_HANDSHAKE_S3_NEGO;
}

static void OpenChaoJi_gbt27930_a_evcc_prev_handshake_s4_recognize(struct OpenChaoJi_evcc_context * context)
{
    context->running_data.a->msg_crm_ok = 0;
}
static void OpenChaoJi_gbt27930_a_evcc_post_handshake_s4_recognize(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_handshake_s4_recognize(struct OpenChaoJi_evcc_context * context)
{
    // TVPbrm定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvp_brm))
    {
        // 发送BRM报文
        LOG_INFO("[%d]Handshake S4 send brm", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BRM, (uint8_t *)(&context->running_data.a->msg_brm), sizeof(context->running_data.a->msg_brm));

        // 重置TVPbrm
        LOG_INFO("[%d]Handshake S4 reset timer TVPbrm", context->tag);
        OpenChaoJi_os_soft_timer_reset(&context->running_data.a->tvp_brm);
    }

    // 接收充电机CRM_AA报文
    if (context->running_data.a->msg_crm_ok && \
        context->running_data.a->msg_crm.recognition_result == OPENCHAOJI_GBT27930_A_RECOGNIZE_TYPE_RECOGNIZED)
    {
        LOG_NOTICE("[%d]Handshake S4 crm_AA received", context->tag);

        // 关闭TVPbrm
        LOG_INFO("[%d]Handshake S4 stop timer TVPbrm", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_brm);

        // 关闭TVOcrmAA
        LOG_INFO("[%d]Handshake S4 stop timer TVPcrmAA", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_crm_aa);

        // 进入S5
        LOG_NOTICE("[%d]Handshake S4 To S5", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_HANDSHAKE_S5_SUCCEED;
    }

    // TVOcrmAA定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvo_crm_aa))
    {
        LOG_ERR("[%d]Handshake S4 crm_AA timeout", context->tag);

        // 关闭TVPbrm
        LOG_INFO("[%d]Handshake S4 stop timer TVPbrm", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_brm);

        // 发送BEM报文, 此处只更新错误代码, 进入错误处理阶段后执行发送
        context->running_data.a->msg_bem.tout_code.bits.crm_aa = 0x01; // CRM_AA超时

        // 进入S6
        LOG_ERR("[%d]Handshake S4 To S6", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_HANDSHAKE_S6_ERROR;
    }

    // 未收到, 未超时, 继续等待, 保持S4
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_HANDSHAKE_S4_RECOGINZE;
}

static void OpenChaoJi_gbt27930_a_evcc_prev_handshake_s5_succeed(struct OpenChaoJi_evcc_context * context) {}
static void OpenChaoJi_gbt27930_a_evcc_post_handshake_s5_succeed(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_handshake_s5_succeed(struct OpenChaoJi_evcc_context * context)
{
    // 进入充电参数配置阶段
    LOG_NOTICE("[%d]Handshake S5 To Config S0", context->tag);
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CONFIG_S0_INIT;
}

static void OpenChaoJi_gbt27930_a_evcc_prev_handshake_s6_error(struct OpenChaoJi_evcc_context * context) {}
static void OpenChaoJi_gbt27930_a_evcc_post_handshake_s6_error(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_handshake_s6_error(struct OpenChaoJi_evcc_context * context)
{
    // 进入错误处理阶段
    LOG_ERR("[%d]Hhandshake S6 To Error S0", context->tag);
    context->running_data.a->stop_ticks = OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVO_STOP_TIMEOUT;
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_ERROR_S0_INIT;
}

static void OpenChaoJi_gbt27930_a_evcc_prev_handshake_s7_finished(struct OpenChaoJi_evcc_context * context) {}
static void OpenChaoJi_gbt27930_a_evcc_post_handshake_s7_finished(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_handshake_s7_finished(struct OpenChaoJi_evcc_context * context)
{
    // 复位充电启动标识
    context->app_permit_charge = 0;

    LOG_ERR("[%d]Handshake Status Sleep", context->tag);

    // 退出充电
    LOG_ERR("[%d]Handshake S7 Return to Idle", context->tag);
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_IDLE_S0_IDLE;
}

const struct OpenChaoJi_evcc_module_status c_sytem_a_evcc_status_array_handshake[OPENCHAOJI_GBT27930_A_EVCC_STATUS_HANDSHAKE_NUM] = {
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_HANDSHAKE_S0_INIT,
        .name = "Handshake.S0.Init",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_handshake_s0_init,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_handshake_s0_init,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_handshake_s0_init,
    },
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_HANDSHAKE_S1_CONNECT,
        .name = "Handshake.S1.Connect",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_handshake_s1_connect,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_handshake_s1_connect,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_handshake_s1_connect,
    },
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_HANDSHAKE_S2_WAIT_NEGO,
        .name = "Handshake.S2.Wait_Nego",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_handshake_s2_wait_nego,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_handshake_s2_wait_nego,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_handshake_s2_wait_nego,
    },
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_HANDSHAKE_S3_NEGO,
        .name = "Handshake.S3.Nego",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_handshake_s3_nego,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_handshake_s3_nego,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_handshake_s3_nego,
    },
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_HANDSHAKE_S4_RECOGINZE,
        .name = "Handshake.S4.Recognize",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_handshake_s4_recognize,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_handshake_s4_recognize,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_handshake_s4_recognize,
    },
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_HANDSHAKE_S5_SUCCEED,
        .name = "Handshake.S5.Succeed",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_handshake_s5_succeed,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_handshake_s5_succeed,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_handshake_s5_succeed,
    },
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_HANDSHAKE_S6_ERROR,
        .name = "Handshake.S6.Error",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_handshake_s6_error,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_handshake_s6_error,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_handshake_s6_error,
    },
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_HANDSHAKE_S7_FINISHED,
        .name = "Handshake.S7.Finished",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_handshake_s7_finished,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_handshake_s7_finished,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_handshake_s7_finished,
    },
};

const struct OpenChaoJi_evcc_module c_gbt27930_a_evcc_module_handshake =
{
    .module_id = OPENCHAOJI_GBT27930_A_MODULE_HANDSHAKE,
    .name = "Handshake",
    .status_array = c_sytem_a_evcc_status_array_handshake,
    .status_array_len = OPENCHAOJI_GBT27930_A_EVCC_STATUS_HANDSHAKE_NUM,
};

/* 参数配置 */

static void OpenChaoJi_gbt27930_a_evcc_prev_config_s0_init(struct OpenChaoJi_evcc_context * context)
{
    LOG_NOTICE("[%d]Config Status Start", context->tag);
    LOG_NOTICE("[%d]Config S0 init", context->tag);
    memset(&context->running_data.a->config, 0, sizeof(context->running_data.a->config));
}
static void OpenChaoJi_gbt27930_a_evcc_post_config_s0_init(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_config_s0_init(struct OpenChaoJi_evcc_context * context)
{
    // 发送BCP报文
    LOG_INFO("[%d]Config S0 send bcp", context->tag);
    OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BCP, (uint8_t *)(&context->running_data.a->msg_bcp), sizeof(context->running_data.a->msg_bcp));

    // 打开TVPbcp
    LOG_INFO("[%d]Config S0 start timer TVPbcp", context->tag);
    OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvp_bcp, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVPBCP);

    // 打开TVOcml
    LOG_INFO("[%d]Config S0 start timer TVOcml", context->tag);
    OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvo_cml, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVOCML);

    // 进入S1
    LOG_NOTICE("[%d]Config S0 To S1", context->tag);
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CONFIG_S1_WAIT_CML;
}

static void OpenChaoJi_gbt27930_a_evcc_prev_config_s1_wait_cml(struct OpenChaoJi_evcc_context * context)
{
    context->running_data.a->msg_cml_ok = 0;
}
static void OpenChaoJi_gbt27930_a_evcc_post_config_s1_wait_cml(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_config_s1_wait_cml(struct OpenChaoJi_evcc_context * context)
{
    // TVPbcp定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvp_bcp))
    {
        // 发送BCP报文
        LOG_INFO("[%d]Config S1 send bcp", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BCP, (uint8_t *)(&context->running_data.a->msg_bcp), sizeof(context->running_data.a->msg_bcp));

        // 重置TVPbcp
        LOG_INFO("[%d]Config S1 reset timer TVPbcp", context->tag);
        OpenChaoJi_os_soft_timer_reset(&context->running_data.a->tvp_bcp);
    }

    // 接收充电机CML报文
    if (context->running_data.a->msg_cml_ok == 1)
    {
        LOG_NOTICE("[%d]Config S1 cml received", context->tag);

        // 关闭TVOcml
        LOG_INFO("[%d]Config S1 stop timer TVOcml", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_cml);

        // 进入S2
        LOG_NOTICE("[%d]Config S1 To S2", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CONFIG_S2_CHECK_PARAM;
    }

    // TVOcml定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvo_cml))
    {
        LOG_ERR("[%d]Config S1 cml timeout", context->tag);

        // 关闭TVPbcp
        LOG_INFO("[%d]Config S1 stop timer TVPbcp", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bcp);

        // 发BEM报文, 此处只更新错误代码, 进入错误处理阶段后执行发送
        context->running_data.a->msg_bem.tout_code.bits.cml = 0x01; // CML超时

        // 进入S8
        LOG_ERR("[%d]Config S1 To S8", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CONFIG_S8_ERROR;
    }

    // 未收到, 未超时, 继续等待, 保持S1
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CONFIG_S1_WAIT_CML;
}

static void OpenChaoJi_gbt27930_a_evcc_prev_config_s2_check_param(struct OpenChaoJi_evcc_context * context)
{
    context->running_data.a->config.time_sync = 0;
    context->running_data.a->msg_cts_ok = 0;
}
static void OpenChaoJi_gbt27930_a_evcc_post_config_s2_check_param(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_config_s2_check_param(struct OpenChaoJi_evcc_context * context)
{
    // 充电机参数匹配结果
    LOG_NOTICE("allow_voltage = [%d]  min_output_voltage = [%d] measured_voltage = [%d] max_output_voltage =[%d]",\
    context->running_data.a->msg_bcp.allow_voltage, context->running_data.a->msg_cml.min_output_voltage,\
    context->running_data.a->msg_bcp.measured_voltage, context->running_data.a->msg_cml.max_output_voltage\
    );
    if (context->running_data.a->msg_bcp.allow_voltage >= context->running_data.a->msg_cml.min_output_voltage && \
        context->running_data.a->msg_bcp.measured_voltage <= context->running_data.a->msg_cml.max_output_voltage) // 参数匹配成功
    {
        LOG_NOTICE("[%d]Config S2 cml param match", context->tag);

        // 再次获取EVCC配置参数
        struct OpenChaoJi_gbt27930_a_msg_bcp tmp_bcp;
        memset(&tmp_bcp, 0, sizeof(tmp_bcp));
        tmp_bcp.allow_cellvolt = OpenChaoJi_evcc_hal_get_allow_cellvolt(context->hal_handle);
        tmp_bcp.allow_current = 4000 - OpenChaoJi_evcc_hal_get_allow_current(context->hal_handle);
        tmp_bcp.rated_energy = OpenChaoJi_evcc_hal_get_rated_energy(context->hal_handle);
        tmp_bcp.allow_voltage = OpenChaoJi_evcc_hal_get_allow_voltage(context->hal_handle);
        tmp_bcp.allow_tempera = 50 + OpenChaoJi_evcc_hal_get_allow_tempera(context->hal_handle);
        tmp_bcp.batt_soc = OpenChaoJi_evcc_hal_get_batt_soc(context->hal_handle);
        tmp_bcp.measured_voltage = OpenChaoJi_evcc_hal_get_measured_voltage(context->hal_handle);

        // 确认是否需要变更BCP参数
        if (memcmp(&tmp_bcp, &context->running_data.a->msg_bcp, sizeof(tmp_bcp)) != 0) // 需要变更参数
        {
            context->running_data.a->msg_bcp = tmp_bcp; // 更新BCP参数
            // 进入S3
            LOG_NOTICE("[%d]Config S2 To S3", context->tag);
            return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CONFIG_S3_UPDATE_PARAM;
        }
        else
        {
            // 关闭TVPbcp
            LOG_INFO("[%d]Config S2 stop timer TVPbcp", context->tag);
            OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bcp);

            // 准备BRO内容, SPN2829=0x00
            context->running_data.a->msg_bro.bms_ready = OPENCHAOJI_GBT27930_A_READY_TYPE_NOT_READY;

            // 发送BRO报文
            LOG_INFO("[%d]Config S2 send bro_00", context->tag);
            OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BRO, (uint8_t *)(&context->running_data.a->msg_bro), sizeof(context->running_data.a->msg_bro));

            // 打开TVPbro
            LOG_INFO("[%d]Config S2 start timer TVPbro", context->tag);
            OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvp_bro, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVPBRO);

            // 进入S4
            LOG_NOTICE("[%d]Config S2 To S4", context->tag);
            return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CONFIG_S4_WAIT_BRO;
        }
    }
    else // 参数匹配失败
    {
        LOG_NOTICE("[%d]Config S2 cml param mismatch", context->tag);

        // 发送CST报文, 此处只更新故障代码, 在故障处理阶段执行发送
        context->running_data.a->msg_bst.error_code.bits.param = 0x01; // 充电参数不匹配

        // 进入S7
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CONFIG_S7_FAULT;
    }
}

static void OpenChaoJi_gbt27930_a_evcc_prev_config_s3_update_param(struct OpenChaoJi_evcc_context * context)
{
    context->running_data.a->config.param_update_delay = 0;
}
static void OpenChaoJi_gbt27930_a_evcc_post_config_s3_update_param(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_config_s3_update_param(struct OpenChaoJi_evcc_context * context)
{
    // TVPbcp定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvp_bcp))
    {
        // 发送BCP报文
        LOG_INFO("[%d]Config S3 send bcp", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BCP, (uint8_t *)(&context->running_data.a->msg_bcp), sizeof(context->running_data.a->msg_bcp));

        // 重置TVPbcp
        LOG_INFO("[%d]Config S3 reset timer TVPbcp", context->tag);
        OpenChaoJi_os_soft_timer_reset(&context->running_data.a->tvp_bcp);

        // 记录参数更新后BCP发送次数
        context->running_data.a->config.param_update_delay++;
    }

    // 更新BCP报文的参数后, 车辆宜至少再发送2帧更新参数后的BCP报文
    if (context->running_data.a->config.param_update_delay > 2)
    {
        // 关闭TVPbcp
        LOG_INFO("[%d]Config S3 stop timer TVPbcp", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bcp);

        // 准备BRO内容, SPN2829=0x00
        context->running_data.a->msg_bro.bms_ready = OPENCHAOJI_GBT27930_A_READY_TYPE_NOT_READY;

        // 发送BRO报文
        LOG_INFO("[%d]Config S3 send bro_00", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BRO, (uint8_t *)(&context->running_data.a->msg_bro), sizeof(context->running_data.a->msg_bro));

        // 打开TVPbro
        LOG_INFO("[%d]Config S3 start timer TVPbro", context->tag);
        OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvp_bro, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVPBRO);

        // 进入S4
        LOG_NOTICE("[%d]Config S3 To S4", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CONFIG_S4_WAIT_BRO;
    }

    // 未超时, 继续等待, 保持S3
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CONFIG_S3_UPDATE_PARAM;
}

static void OpenChaoJi_gbt27930_a_evcc_prev_config_s4_wait_bro(struct OpenChaoJi_evcc_context * context) {}
static void OpenChaoJi_gbt27930_a_evcc_post_config_s4_wait_bro(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_config_s4_wait_bro(struct OpenChaoJi_evcc_context * context)
{
    if (context->running_data.a->msg_bro.bms_ready == OPENCHAOJI_GBT27930_A_READY_TYPE_NOT_READY)
    {
        //闭合车辆断开装置
        LOG_NOTICE("[%d]Config S4 close C5 C6", context->tag);
        OpenChaoJi_evcc_hal_gbt_close_dc_relay(context->hal_handle,1);

        // 车辆状态就绪 SPN2829=0xAA
        context->running_data.a->msg_bro.bms_ready = OPENCHAOJI_GBT27930_A_READY_TYPE_READY;

        LOG_NOTICE("[%d]Config S4 evcc is ready", context->tag);
    }

    // TVPbro定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvp_bro))
    {
        // 发送BRO报文
        LOG_INFO("[%d]Config S4 send bro_00", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BRO, (uint8_t *)(&context->running_data.a->msg_bro), sizeof(context->running_data.a->msg_bro));

        // 重置TVPbro
        LOG_INFO("[%d]Config S4 reset timer TVPbro", context->tag);
        OpenChaoJi_os_soft_timer_reset(&context->running_data.a->tvp_bro);

        if (context->running_data.a->msg_bro.bms_ready == OPENCHAOJI_GBT27930_A_READY_TYPE_READY)
        {
            // 打开TVOcro
            LOG_INFO("[%d]Config S4 start timer TVOcro", context->tag);
            OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvo_cro, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVOCRO);

            // 打开TVOcroAA
            LOG_INFO("[%d]Config S4 start timer TVOcroAA", context->tag);
            OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvo_cro_aa, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVOCRO_AA);

            // 进入S5
            LOG_NOTICE("[%d]Config S4 To S5", context->tag);
            return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CONFIG_S5_WAIT_CRO;
        }
    }

    // 未就绪, 继续等待, 保持S4
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CONFIG_S4_WAIT_BRO;
}

static void OpenChaoJi_gbt27930_a_evcc_prev_config_s5_wait_cro(struct OpenChaoJi_evcc_context * context)
{
    context->running_data.a->msg_cro_ok = 0;
}
static void OpenChaoJi_gbt27930_a_evcc_post_config_s5_wait_cro(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_config_s5_wait_cro(struct OpenChaoJi_evcc_context * context)
{
    // TVPbro定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvp_bro))
    {
        // 发送BRO报文
        LOG_INFO("[%d]Config S5 send bro_AA", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BRO, (uint8_t *)(&context->running_data.a->msg_bro), sizeof(context->running_data.a->msg_bro));

        // 重置TVPbro
        LOG_INFO("[%d]Config S5 reset timer TVPbro", context->tag);
        OpenChaoJi_os_soft_timer_reset(&context->running_data.a->tvp_bro);
    }

    // 接收充电机CRO报文
    if (context->running_data.a->msg_cro_ok)
    {
        context->running_data.a->msg_cro_ok = 0;

        // 重置TVOcro
        LOG_INFO("[%d]Config S5 reset timer TVOcro", context->tag);
        OpenChaoJi_os_soft_timer_reset(&context->running_data.a->tvo_cro);

        // SPN2830=0xAA
        if (context->running_data.a->msg_cro.charger_ready_for_charging == OPENCHAOJI_GBT27930_A_READY_TYPE_READY)
        {
            LOG_NOTICE("[%d]Config S5 cro_AA received", context->tag);

            // 关闭TVPbro
            LOG_INFO("[%d]Config S5 stop timer TVPbro", context->tag);
            OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bro);

            // 关闭TVOcro
            LOG_INFO("[%d]Config S5 stop timer TVOcro", context->tag);
            OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_cro);

            // 关闭TVOcroAA
            LOG_INFO("[%d]Config S5 stop timer TVOcroAA", context->tag);
            OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_cro_aa);

            // 进入S6
            LOG_NOTICE("[%d]Config S5 To S6", context->tag);
            return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CONFIG_S6_SUCCEED;
        }
    }

    // TVOcro定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvo_cro))
    {
        LOG_ERR("[%d]Config S5 cro timeout", context->tag);

        // 关闭TVPbro
        LOG_INFO("[%d]Config S5 stop timer TVPbro", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bro);

        // 关闭TVOcroAA
        LOG_INFO("[%d]Config S5 stop timer TVOcroAA", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_cro_aa);

        // 发送BEM报文, 此处只更新错误代码, 进入错误处理阶段后执行发送
        context->running_data.a->msg_bem.tout_code.bits.cro = 0x01; // CRO超时

        // 进入S8
        LOG_ERR("[%d]Config S5 To S8", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CONFIG_S8_ERROR;
    }

    // TVOcroAA定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvo_cro_aa))
    {
        LOG_ERR("[%d]Config S5 cro_AA timeout", context->tag);

        // 关闭TVPbro
        LOG_INFO("[%d]Config S5 stop timer TVPbro", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bro);

        // 关闭TVOcro
        LOG_INFO("[%d]Config S5 stop timer TVOcro", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_cro);

        // 发送BEM报文, 此处只更新错误代码, 进入错误处理阶段后执行发送
        context->running_data.a->msg_bem.tout_code.bits.cro = 0x01; // CRO超时

        // 进入S8
        LOG_ERR("[%d]Config S5 To S8", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CONFIG_S8_ERROR;
    }

    // 未收到, 未超时, 继续等待, 保持S5
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CONFIG_S5_WAIT_CRO;
}

static void OpenChaoJi_gbt27930_a_evcc_prev_config_s6_succeed(struct OpenChaoJi_evcc_context * context) {}
static void OpenChaoJi_gbt27930_a_evcc_post_config_s6_succeed(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_config_s6_succeed(struct OpenChaoJi_evcc_context * context)
{
    // 进入充电阶段
    LOG_NOTICE("[%d]Config S6 To Charge S0", context->tag);
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S0_INIT;
}

static void OpenChaoJi_gbt27930_a_evcc_prev_config_s7_fault(struct OpenChaoJi_evcc_context * context) {}
static void OpenChaoJi_gbt27930_a_evcc_post_config_s7_fault(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_config_s7_fault(struct OpenChaoJi_evcc_context * context)
{
    // 进入故障处理阶段
    LOG_ERR("[%d]Config S7 To Charge S5", context->tag);
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S5_EV_STOP;
}

static void OpenChaoJi_gbt27930_a_evcc_prev_config_s8_error(struct OpenChaoJi_evcc_context * context) {}
static void OpenChaoJi_gbt27930_a_evcc_post_config_s8_error(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_config_s8_error(struct OpenChaoJi_evcc_context * context)
{
    // 进入错误处理阶段
    LOG_ERR("[%d]Config S7 To Error S0", context->tag);
    context->running_data.a->stop_ticks = OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVO_STOP_TIMEOUT;
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_ERROR_S0_INIT;
}

const struct OpenChaoJi_evcc_module_status c_sytem_a_evcc_status_array_config[OPENCHAOJI_GBT27930_A_EVCC_STATUS_CONFIG_NUM] = {
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CONFIG_S0_INIT,
        .name = "Config.S0.Init",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_config_s0_init,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_config_s0_init,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_config_s0_init,
    },
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CONFIG_S1_WAIT_CML,
        .name = "Config.S1.Wait_CML",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_config_s1_wait_cml,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_config_s1_wait_cml,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_config_s1_wait_cml,
    },
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CONFIG_S2_CHECK_PARAM,
        .name = "Config.S2.Check_Param",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_config_s2_check_param,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_config_s2_check_param,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_config_s2_check_param,
    },
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CONFIG_S3_UPDATE_PARAM,
        .name = "Config.S3.Update_Param",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_config_s3_update_param,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_config_s3_update_param,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_config_s3_update_param,
    },
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CONFIG_S4_WAIT_BRO,
        .name = "Config.S4.Wait_BRO",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_config_s4_wait_bro,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_config_s4_wait_bro,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_config_s4_wait_bro,
    },
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CONFIG_S5_WAIT_CRO,
        .name = "Config.S5.Wait_CRO",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_config_s5_wait_cro,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_config_s5_wait_cro,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_config_s5_wait_cro,
    },
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CONFIG_S6_SUCCEED,
        .name = "Config.S6.Succeed",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_config_s6_succeed,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_config_s6_succeed,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_config_s6_succeed,
    },
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CONFIG_S7_FAULT,
        .name = "Config.S7.Fault",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_config_s7_fault,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_config_s7_fault,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_config_s7_fault,
    },
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CONFIG_S8_ERROR,
        .name = "Config.S8.Error",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_config_s8_error,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_config_s8_error,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_config_s8_error,
    },
};

const struct OpenChaoJi_evcc_module c_gbt27930_a_evcc_module_config =
{
    .module_id = OPENCHAOJI_GBT27930_A_MODULE_CONFIG,
    .name = "Config",
    .status_array = c_sytem_a_evcc_status_array_config,
    .status_array_len = OPENCHAOJI_GBT27930_A_EVCC_STATUS_CONFIG_NUM,
};

/* 充电 */

static void OpenChaoJi_gbt27930_a_evcc_prev_charge_s0_init(struct OpenChaoJi_evcc_context * context)
{
    LOG_NOTICE("[%d]Charge Status Start", context->tag);
    LOG_NOTICE("[%d]Charge S0 init", context->tag);
    memset(&context->running_data.a->charge, 0, sizeof(context->running_data.a->charge));

    LOG_STATUS_PREV("[%d] battery prepare for charging", context->tag);
    OpenChaoJi_evcc_hal_battery_prepare(context->hal_handle);
}
static void OpenChaoJi_gbt27930_a_evcc_post_charge_s0_init(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_charge_s0_init(struct OpenChaoJi_evcc_context * context)
{
    // 向车查询车辆充电需求
    OpenChaoJi_evcc_app_get_charging_requirement(context, &context->running_data.a->charge.requirement_parameter);
    context->running_data.a->msg_bcl.target_voltage = context->running_data.a->charge.requirement_parameter.voltage;        // 车辆接口充电电压需求
    context->running_data.a->msg_bcl.target_current = 4000 - context->running_data.a->charge.requirement_parameter.current; // 车辆接口充电电流需求
    context->running_data.a->msg_bcl.charge_mode = context->running_data.a->charge.requirement_parameter.charge_mode;       // 充电模式

    // 发送BCL报文
    LOG_INFO("[%d]Charge S0 send bcl", context->tag);
    OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BCL, (uint8_t *)(&context->running_data.a->msg_bcl), sizeof(context->running_data.a->msg_bcl));

    // 打开TVPbcl
    LOG_INFO("[%d]Charge S0 start timer TVPbcl", context->tag);
    OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvp_bcl, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVPBCL);

    // 更新BCS报文内容
    context->running_data.a->msg_bcs.measured_voltage = OpenChaoJi_evcc_hal_get_measured_voltage(context->hal_handle); // 车辆接口当前电压测量值
    context->running_data.a->msg_bcs.measured_current = 4000 - OpenChaoJi_evcc_hal_get_measured_current(context->hal_handle); // 车辆接口当前电流测量值
    context->running_data.a->msg_bcs.soc = OpenChaoJi_evcc_hal_get_batt_soc(context->hal_handle) / 10; // 当前荷电状态, 注意分辨率
    context->running_data.a->msg_bcs.expected_time = OpenChaoJi_evcc_hal_get_expected_time(context->hal_handle); // 估算剩余充电时间
    struct OpenChaoJi_evcc_hal_batt_cellvolt temp = OpenChaoJi_evcc_hal_get_max_cellvolt(context->hal_handle);
    context->running_data.a->msg_bcs.max_cellvolt.bits.group = temp.group; // 最高单体蓄电池电压分组号
    context->running_data.a->msg_bcs.max_cellvolt.bits.value = temp.voltage; // 最高单体蓄电池电压值

    // 发送BCS报文
    LOG_INFO("[%d]Charge S0 send bcs", context->tag);
    OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BCS, (uint8_t *)(&context->running_data.a->msg_bcs), sizeof(context->running_data.a->msg_bcs));

    // 打开TVPbcs
    LOG_INFO("[%d]Charge S0 start timer TVPbcs", context->tag);
    OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvp_bcs, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVPBCS);

    // 打开TVOccs
    LOG_INFO("[%d]Charge S0 start timer TVOccs", context->tag);
    OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvo_ccs, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVOCCS);

    // 进入S1
    LOG_NOTICE("[%d]Charge S0 To S1", context->tag);
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S1_WAIT_CCS;
}

static void OpenChaoJi_gbt27930_a_evcc_prev_charge_s1_wait_ccs(struct OpenChaoJi_evcc_context * context)
{
    context->running_data.a->msg_ccs_ok = 0;
}
static void OpenChaoJi_gbt27930_a_evcc_post_charge_s1_wait_ccs(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_charge_s1_wait_ccs(struct OpenChaoJi_evcc_context * context)
{
    // TVPbcl定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvp_bcl))
    {
        // 向车查询车辆充电需求
        OpenChaoJi_evcc_app_get_charging_requirement(context, &context->running_data.a->charge.requirement_parameter);
        context->running_data.a->msg_bcl.target_voltage = context->running_data.a->charge.requirement_parameter.voltage;        // 车辆接口充电电压需求
        context->running_data.a->msg_bcl.target_current = 4000 - context->running_data.a->charge.requirement_parameter.current; // 车辆接口充电电流需求
        context->running_data.a->msg_bcl.charge_mode = context->running_data.a->charge.requirement_parameter.charge_mode;       // 充电模式

        // 发送BCL报文
        LOG_INFO("[%d]Charge S1 send bcl", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BCL, (uint8_t *)(&context->running_data.a->msg_bcl), sizeof(context->running_data.a->msg_bcl));

        // 重置TVPbcl
        LOG_INFO("[%d]Charge S1 reset timer TVPbcl", context->tag);
        OpenChaoJi_os_soft_timer_reset(&context->running_data.a->tvp_bcl);
    }

    // TVPbcs定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvp_bcs))
    {
        // 更新BCS报文内容
        context->running_data.a->msg_bcs.measured_voltage = OpenChaoJi_evcc_hal_get_measured_voltage(context->hal_handle); // 车辆接口当前电压测量值
        context->running_data.a->msg_bcs.measured_current = 4000 - OpenChaoJi_evcc_hal_get_measured_current(context->hal_handle); // 车辆接口当前电流测量值
        context->running_data.a->msg_bcs.soc = OpenChaoJi_evcc_hal_get_batt_soc(context->hal_handle) / 10; // 当前荷电状态, 注意分辨率
        context->running_data.a->msg_bcs.expected_time = OpenChaoJi_evcc_hal_get_expected_time(context->hal_handle); // 估算剩余充电时间
        struct OpenChaoJi_evcc_hal_batt_cellvolt temp = OpenChaoJi_evcc_hal_get_max_cellvolt(context->hal_handle);
        context->running_data.a->msg_bcs.max_cellvolt.bits.group = temp.group; // 最高单体蓄电池电压分组号
        context->running_data.a->msg_bcs.max_cellvolt.bits.value = temp.voltage; // 最高单体蓄电池电压值

        // 发送BCS报文
        LOG_INFO("[%d]Charge S1 send bcs", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BCS, (uint8_t *)(&context->running_data.a->msg_bcs), sizeof(context->running_data.a->msg_bcs));

        // 重置TVPbcs
        LOG_INFO("[%d]Charge S1 reset timer TVPbcs", context->tag);
        OpenChaoJi_os_soft_timer_reset(&context->running_data.a->tvp_bcs);
    }

    // 接收充电机CCS报文
    if (context->running_data.a->msg_ccs_ok)
    {
        context->running_data.a->msg_ccs_ok = 0;

        LOG_NOTICE("[%d]Charge S1 ccs received", context->tag);

        // 重置TVOccs
        LOG_INFO("[%d]Charge S1 reset timer TVOccs", context->tag);
        OpenChaoJi_os_soft_timer_reset(&context->running_data.a->tvo_ccs);

        // 更新BSM报文内容
        struct OpenChaoJi_evcc_hal_batt_cellvolt max_cellvolt = OpenChaoJi_evcc_hal_get_max_cellvolt(context->hal_handle);
        context->running_data.a->msg_bsm.max_cellvolt_id = max_cellvolt.id - 1; // 最高单体蓄电池电压所在编号
        struct OpenChaoJi_evcc_hal_batt_tempera max_tempera = OpenChaoJi_evcc_hal_get_max_tempera(context->hal_handle);
        context->running_data.a->msg_bsm.max_tempera = (uint8_t)(50 + max_tempera.tempera); // 当前单体蓄电池最高温度
        context->running_data.a->msg_bsm.max_tempera_id = max_tempera.id - 1; // 最高动力蓄电池温度检测点编号
        struct OpenChaoJi_evcc_hal_batt_tempera min_tempera = OpenChaoJi_evcc_hal_get_min_tempera(context->hal_handle);
        context->running_data.a->msg_bsm.min_tempera = (uint8_t)(50 + min_tempera.tempera); // 当前单体蓄电池最低温度
        context->running_data.a->msg_bsm.min_tempera_id = min_tempera.id - 1; // 最低动力蓄电池温度检测点编号
        union OpenChaoJi_evcc_hal_batt_state state = OpenChaoJi_evcc_hal_get_batt_state(context->hal_handle);
        context->running_data.a->msg_bsm.batt_state.all = state.all; // 电池状态及充电允许标识

        // 发送BSM报文
        LOG_INFO("[%d]Charge S1 send bsm", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BSM, (uint8_t *)(&context->running_data.a->msg_bsm), sizeof(context->running_data.a->msg_bsm));

        // 打开TVPbsm
        LOG_INFO("[%d]Charge S1 start timer TVPbsm", context->tag);
        OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvp_bsm, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVPBSM);

        // 更新BMV报文内容
        int i;
        unsigned char cellvolt_group[256] = {0};
        unsigned int cellvolt_value[256] = {0};
        unsigned int cellvolt_num = OpenChaoJi_evcc_hal_get_cellvolt_num(context->hal_handle); // 单体数量
        if (cellvolt_num > 256) cellvolt_num = 256;
        context->running_data.a->msg_bmv.cellvolt_num = cellvolt_num;
        OpenChaoJi_evcc_hal_get_cellvolt(context->hal_handle, cellvolt_group, cellvolt_value); // 单体信息
        for (i=0; i<cellvolt_num; i++)
        {
            context->running_data.a->msg_bmv.cellvolt[i].bits.group = cellvolt_group[i]; // 电池分组号
            context->running_data.a->msg_bmv.cellvolt[i].bits.value = cellvolt_value[i]; // 单体蓄电池电压值
        }

        // 发送BMV报文
        LOG_INFO("[%d]Charge S1 send bmv", context->tag);
        // OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BMV, (uint8_t *)(&context->running_data.a->msg_bmv), sizeof(context->running_data.a->msg_bmv));

        // 打开TVPbmv
        LOG_INFO("[%d]Charge S1 start timer TVPbmv", context->tag);
        // OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvp_bmv, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVPBMV);

        // 更新BMT报文内容
        int tempera[128] = {0};
        unsigned int tempera_num = OpenChaoJi_evcc_hal_get_tempera_num(context->hal_handle);
        if (tempera_num > 128) tempera_num = 128;
        context->running_data.a->msg_bmt.tempera_num = tempera_num;
        OpenChaoJi_evcc_hal_get_tempera(context->hal_handle, tempera);
        for (i=0; i<tempera_num; i++)
        {
            context->running_data.a->msg_bmt.tempera[i] = (uint8_t)(50 + tempera[i]); // 动力蓄电池温度
        }

        // 发送BMT报文
        LOG_INFO("[%d]Charge S1 send bmt", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BMT, (uint8_t *)(&context->running_data.a->msg_bmt), sizeof(context->running_data.a->msg_bmt));

        // 打开TVPbmt
        LOG_INFO("[%d]Charge S1 start timer TVPbmt", context->tag);
        OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvp_bmt, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVPBMT);

        // 判断充电机是否允许充电
        if (context->running_data.a->msg_ccs.state.bits.charging_permissible == OPENCHAOJI_GBT27930_A_PAUSE_STATUS_CHARGE)
        {
            // 充电机允许充电, 进入S2
            LOG_NOTICE("[%d]Charge S1 To S2", context->tag);
            return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S2_ENERGY_TRANS;
        }
        else
        {
            LOG_NOTICE("[%d]Charge S1 SECC Start Suspend", context->tag);

            // 打开TVOcsup
            LOG_INFO("[%d]Charge S1 start timer TVOcsup", context->tag);
            OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvo_csup, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVOCSUP);

            // 充电机暂停充电, 进入S3
            LOG_NOTICE("[%d]Charge S1 To S3", context->tag);
            return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S3_SE_SUSPEND;
        }
    }

    // TVOccs定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvo_ccs))
    {
        LOG_ERR("[%d]Charge S1 ccs timeout", context->tag);

        // 发BEM报文, 此处只更新错误代码, 进入错误处理阶段后执行发送
        context->running_data.a->msg_bem.tout_code.bits.ccs = 0x01; // CCS超时

        // 进入S8
        LOG_ERR("[%d]Charge S1 To S8", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S8_ERROR;
    }

    // 未收到, 未超时, 继续等待, 保持S1
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S1_WAIT_CCS;
}

static void OpenChaoJi_gbt27930_a_evcc_prev_charge_s2_energy_trans(struct OpenChaoJi_evcc_context * context) {}
static void OpenChaoJi_gbt27930_a_evcc_post_charge_s2_energy_trans(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_charge_s2_energy_trans(struct OpenChaoJi_evcc_context * context)
{
    // TVPbcl定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvp_bcl))
    {
        // 向车查询车辆充电需求
        OpenChaoJi_evcc_app_get_charging_requirement(context, &context->running_data.a->charge.requirement_parameter);
        context->running_data.a->msg_bcl.target_voltage = context->running_data.a->charge.requirement_parameter.voltage;        // 车辆接口充电电压需求
        context->running_data.a->msg_bcl.target_current = 4000 - context->running_data.a->charge.requirement_parameter.current; // 车辆接口充电电流需求
        context->running_data.a->msg_bcl.charge_mode = context->running_data.a->charge.requirement_parameter.charge_mode;       // 充电模式

        // 发送BCL报文
        LOG_INFO("[%d]Charge S2 send bcl", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BCL, (uint8_t *)(&context->running_data.a->msg_bcl), sizeof(context->running_data.a->msg_bcl));

        // 重置TVPbcl
        LOG_INFO("[%d]Charge S2 reset timer TVPbcl", context->tag);
        OpenChaoJi_os_soft_timer_reset(&context->running_data.a->tvp_bcl);
    }

    // TVPbcs定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvp_bcs))
    {
        // 更新BCS报文内容
        context->running_data.a->msg_bcs.measured_voltage = OpenChaoJi_evcc_hal_get_measured_voltage(context->hal_handle); // 车辆接口当前电压测量值
        context->running_data.a->msg_bcs.measured_current = 4000 - OpenChaoJi_evcc_hal_get_measured_current(context->hal_handle); // 车辆接口当前电流测量值
        context->running_data.a->msg_bcs.soc = OpenChaoJi_evcc_hal_get_batt_soc(context->hal_handle) / 10; // 当前荷电状态, 注意分辨率
        context->running_data.a->msg_bcs.expected_time = OpenChaoJi_evcc_hal_get_expected_time(context->hal_handle); // 估算剩余充电时间
        struct OpenChaoJi_evcc_hal_batt_cellvolt temp = OpenChaoJi_evcc_hal_get_max_cellvolt(context->hal_handle);
        context->running_data.a->msg_bcs.max_cellvolt.bits.group = temp.group; // 最高单体蓄电池电压分组号
        context->running_data.a->msg_bcs.max_cellvolt.bits.value = temp.voltage; // 最高单体蓄电池电压值

        // 发送BCS报文
        LOG_INFO("[%d]Charge S2 send bcs", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BCS, (uint8_t *)(&context->running_data.a->msg_bcs), sizeof(context->running_data.a->msg_bcs));

        // 重置TVPbcs
        LOG_INFO("[%d]Charge S2 reset timer TVPbcs", context->tag);
        OpenChaoJi_os_soft_timer_reset(&context->running_data.a->tvp_bcs);
    }

    // TVPbsm定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvp_bsm))
    {
        // 更新BSM报文内容
        struct OpenChaoJi_evcc_hal_batt_cellvolt max_cellvolt = OpenChaoJi_evcc_hal_get_max_cellvolt(context->hal_handle);
        context->running_data.a->msg_bsm.max_cellvolt_id = max_cellvolt.id - 1; // 最高单体蓄电池电压所在编号
        struct OpenChaoJi_evcc_hal_batt_tempera max_tempera = OpenChaoJi_evcc_hal_get_max_tempera(context->hal_handle);
        context->running_data.a->msg_bsm.max_tempera = (uint8_t)(50 + max_tempera.tempera); // 当前单体蓄电池最高温度
        context->running_data.a->msg_bsm.max_tempera_id = max_tempera.id - 1; // 最高动力蓄电池温度检测点编号
        struct OpenChaoJi_evcc_hal_batt_tempera min_tempera = OpenChaoJi_evcc_hal_get_min_tempera(context->hal_handle);
        context->running_data.a->msg_bsm.min_tempera = (uint8_t)(50 + min_tempera.tempera); // 当前单体蓄电池最低温度
        context->running_data.a->msg_bsm.min_tempera_id = min_tempera.id - 1; // 最低动力蓄电池温度检测点编号
        union OpenChaoJi_evcc_hal_batt_state state = OpenChaoJi_evcc_hal_get_batt_state(context->hal_handle);
        context->running_data.a->msg_bsm.batt_state.all = state.all; // 电池状态及充电允许标识

        // 发送BSM报文
        LOG_INFO("[%d]Charge S2 send bsm", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BSM, (uint8_t *)(&context->running_data.a->msg_bsm), sizeof(context->running_data.a->msg_bsm));

        // 重置TVPbsm
        LOG_INFO("[%d]Charge S2 reset timer TVPbsm", context->tag);
        OpenChaoJi_os_soft_timer_reset(&context->running_data.a->tvp_bsm);
    }

    // TVPbmv定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvp_bmv))
    {
        // 更新BMV报文内容
        int i;
        unsigned char cellvolt_group[256] = {0};
        unsigned int cellvolt_value[256] = {0};
        unsigned int cellvolt_num = OpenChaoJi_evcc_hal_get_cellvolt_num(context->hal_handle); // 单体数量
        if (cellvolt_num > 256) cellvolt_num = 256;
        context->running_data.a->msg_bmv.cellvolt_num = cellvolt_num;
        OpenChaoJi_evcc_hal_get_cellvolt(context->hal_handle, cellvolt_group, cellvolt_value); // 单体信息
        for (i=0; i<cellvolt_num; i++)
        {
            context->running_data.a->msg_bmv.cellvolt[i].bits.group = cellvolt_group[i]; // 电池分组号
            context->running_data.a->msg_bmv.cellvolt[i].bits.value = cellvolt_value[i]; // 单体蓄电池电压值
        }

        // 发送BMV报文
        LOG_INFO("[%d]Charge S2 send bmv", context->tag);
        // OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BMV, (uint8_t *)(&context->running_data.a->msg_bmv), sizeof(context->running_data.a->msg_bmv));

        // 重置TVPbmv
        LOG_INFO("[%d]Charge S2 reset timer TVPbmv", context->tag);
        // OpenChaoJi_os_soft_timer_reset(&context->running_data.a->tvp_bmv);
    }

    // TVPbmt定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvp_bmt))
    {
        // 更新BMT报文内容
        int i;
        int tempera[128] = {0};
        unsigned int tempera_num = OpenChaoJi_evcc_hal_get_tempera_num(context->hal_handle);
        if (tempera_num > 128) tempera_num = 128;
        context->running_data.a->msg_bmt.tempera_num = tempera_num;
        OpenChaoJi_evcc_hal_get_tempera(context->hal_handle, tempera);
        for (i=0; i<tempera_num; i++)
        {
            context->running_data.a->msg_bmt.tempera[i] = (uint8_t)(50 + tempera[i]); // 动力蓄电池温度
        }

        // 发送BMT报文
        LOG_INFO("[%d]Charge S2 send bmt", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BMT, (uint8_t *)(&context->running_data.a->msg_bmt), sizeof(context->running_data.a->msg_bmt));

        // 重置TVPbmt
        LOG_INFO("[%d]Charge S2 reset timer TVPbmt", context->tag);
        OpenChaoJi_os_soft_timer_reset(&context->running_data.a->tvp_bmt);
    }

    // 接收充电机CCS报文
    if (context->running_data.a->msg_ccs_ok)
    {
        context->running_data.a->msg_ccs_ok = 0;

        LOG_DEBUG("[%d]Charge S2 ccs received", context->tag);

        // 重置TVOccs
        LOG_INFO("[%d]Charge S2 reset timer TVOccs", context->tag);
        OpenChaoJi_os_soft_timer_reset(&context->running_data.a->tvo_ccs);

        // 判断充电机是否允许充电
        if (context->running_data.a->msg_ccs.state.bits.charging_permissible == OPENCHAOJI_GBT27930_A_PAUSE_STATUS_PAUSE) // 暂停充电
        {
            LOG_NOTICE("[%d]Charge S2 SECC Start Suspend", context->tag);

            // 打开TVOcsup
            LOG_INFO("[%d]Charge S2 start timer TVOcsup", context->tag);
            OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvo_csup, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVOCSUP);

            // 充电机暂停充电, 进入S3
            LOG_NOTICE("[%d]Charge S2 To S3", context->tag);
            return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S3_SE_SUSPEND;
        }
    }

    // TVOccs定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvo_ccs))
    {
        LOG_ERR("[%d]Charge S2 ccs timeout", context->tag);

        // 发BEM报文, 此处只更新错误代码, 进入错误处理阶段后执行发送
        context->running_data.a->msg_bem.tout_code.bits.ccs = 0x01; // CCS超时

        // 进入S8
        LOG_ERR("[%d]Charge S2 To S8", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S8_ERROR;
    }

    // 车辆暂停充电-BSM
    union OpenChaoJi_evcc_hal_batt_state state = OpenChaoJi_evcc_hal_get_batt_state(context->hal_handle);
    if (state.bits.charge_enable == OPENCHAOJI_GBT27930_A_PAUSE_STATUS_PAUSE) // 暂停充电
    {
        // BSM报文数据变更为SPN3096=0x00 (状态数据, 实时刷新, 此处无需处理)
        // context->running_data.a->msg_bsm.batt_state.bits.charge_enable = state.bits.charge_enable;

        LOG_NOTICE("[%d]Charge S2 EVCC Start Suspend", context->tag);

        // 车辆暂停充电, 进入S4
        LOG_NOTICE("[%d]Charge S2 To S4", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S4_EV_SUSPEND;
    }

    // 继续等待, 保持S2
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S2_ENERGY_TRANS;
}

static void OpenChaoJi_gbt27930_a_evcc_prev_charge_s3_secc_suspend(struct OpenChaoJi_evcc_context * context) {}
static void OpenChaoJi_gbt27930_a_evcc_post_charge_s3_secc_suspend(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_charge_s3_secc_suspend(struct OpenChaoJi_evcc_context * context)
{
    // TVPbcl定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvp_bcl))
    {
        // 向车查询车辆充电需求
        OpenChaoJi_evcc_app_get_charging_requirement(context, &context->running_data.a->charge.requirement_parameter);
        context->running_data.a->msg_bcl.target_voltage = context->running_data.a->charge.requirement_parameter.voltage;        // 车辆接口充电电压需求
        context->running_data.a->msg_bcl.target_current = 4000 - context->running_data.a->charge.requirement_parameter.current; // 车辆接口充电电流需求
        context->running_data.a->msg_bcl.charge_mode = context->running_data.a->charge.requirement_parameter.charge_mode;       // 充电模式

        // 发送BCL报文
        LOG_INFO("[%d]Charge S3 send bcl", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BCL, (uint8_t *)(&context->running_data.a->msg_bcl), sizeof(context->running_data.a->msg_bcl));

        // 重置TVPbcl
        LOG_INFO("[%d]Charge S3 reset timer TVPbcl", context->tag);
        OpenChaoJi_os_soft_timer_reset(&context->running_data.a->tvp_bcl);
    }

    // TVPbcs定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvp_bcs))
    {
        // 更新BCS报文内容
        context->running_data.a->msg_bcs.measured_voltage = OpenChaoJi_evcc_hal_get_measured_voltage(context->hal_handle); // 车辆接口当前电压测量值
        context->running_data.a->msg_bcs.measured_current = 4000 - OpenChaoJi_evcc_hal_get_measured_current(context->hal_handle); // 车辆接口当前电流测量值
        context->running_data.a->msg_bcs.soc = OpenChaoJi_evcc_hal_get_batt_soc(context->hal_handle) / 10; // 当前荷电状态, 注意分辨率
        context->running_data.a->msg_bcs.expected_time = OpenChaoJi_evcc_hal_get_expected_time(context->hal_handle); // 估算剩余充电时间
        struct OpenChaoJi_evcc_hal_batt_cellvolt temp = OpenChaoJi_evcc_hal_get_max_cellvolt(context->hal_handle);
        context->running_data.a->msg_bcs.max_cellvolt.bits.group = temp.group; // 最高单体蓄电池电压分组号
        context->running_data.a->msg_bcs.max_cellvolt.bits.value = temp.voltage; // 最高单体蓄电池电压值

        // 发送BCS报文
        LOG_INFO("[%d]Charge S3 send bcs", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BCS, (uint8_t *)(&context->running_data.a->msg_bcs), sizeof(context->running_data.a->msg_bcs));

        // 重置TVPbcs
        LOG_INFO("[%d]Charge S3 reset timer TVPbcs", context->tag);
        OpenChaoJi_os_soft_timer_reset(&context->running_data.a->tvp_bcs);
    }

    // TVPbsm定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvp_bsm))
    {
        // 更新BSM报文内容
        struct OpenChaoJi_evcc_hal_batt_cellvolt max_cellvolt = OpenChaoJi_evcc_hal_get_max_cellvolt(context->hal_handle);
        context->running_data.a->msg_bsm.max_cellvolt_id = max_cellvolt.id - 1; // 最高单体蓄电池电压所在编号
        struct OpenChaoJi_evcc_hal_batt_tempera max_tempera = OpenChaoJi_evcc_hal_get_max_tempera(context->hal_handle);
        context->running_data.a->msg_bsm.max_tempera = (uint8_t)(50 + max_tempera.tempera); // 当前单体蓄电池最高温度
        context->running_data.a->msg_bsm.max_tempera_id = max_tempera.id - 1; // 最高动力蓄电池温度检测点编号
        struct OpenChaoJi_evcc_hal_batt_tempera min_tempera = OpenChaoJi_evcc_hal_get_min_tempera(context->hal_handle);
        context->running_data.a->msg_bsm.min_tempera = (uint8_t)(50 + min_tempera.tempera); // 当前单体蓄电池最低温度
        context->running_data.a->msg_bsm.min_tempera_id = min_tempera.id - 1; // 最低动力蓄电池温度检测点编号
        union OpenChaoJi_evcc_hal_batt_state state = OpenChaoJi_evcc_hal_get_batt_state(context->hal_handle);
        context->running_data.a->msg_bsm.batt_state.all = state.all; // 电池状态及充电允许标识

        // 发送BSM报文
        LOG_INFO("[%d]Charge S3 send bsm", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BSM, (uint8_t *)(&context->running_data.a->msg_bsm), sizeof(context->running_data.a->msg_bsm));

        // 重置TVPbsm
        LOG_INFO("[%d]Charge S3 reset timer TVPbsm", context->tag);
        OpenChaoJi_os_soft_timer_reset(&context->running_data.a->tvp_bsm);
    }

    // TVPbmv定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvp_bmv))
    {
        // 更新BMV报文内容
        int i;
        unsigned char cellvolt_group[256] = {0};
        unsigned int cellvolt_value[256] = {0};
        unsigned int cellvolt_num = OpenChaoJi_evcc_hal_get_cellvolt_num(context->hal_handle); // 单体数量
        if (cellvolt_num > 256) cellvolt_num = 256;
        context->running_data.a->msg_bmv.cellvolt_num = cellvolt_num;
        OpenChaoJi_evcc_hal_get_cellvolt(context->hal_handle, cellvolt_group, cellvolt_value); // 单体信息
        for (i=0; i<cellvolt_num; i++)
        {
            context->running_data.a->msg_bmv.cellvolt[i].bits.group = cellvolt_group[i]; // 电池分组号
            context->running_data.a->msg_bmv.cellvolt[i].bits.value = cellvolt_value[i]; // 单体蓄电池电压值
        }

        // 发送BMV报文
        LOG_INFO("[%d]Charge S3 send bmv", context->tag);
        // OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BMV, (uint8_t *)(&context->running_data.a->msg_bmv), sizeof(context->running_data.a->msg_bmv));

        // 重置TVPbmv
        LOG_INFO("[%d]Charge S3 reset timer TVPbmv", context->tag);
        // OpenChaoJi_os_soft_timer_reset(&context->running_data.a->tvp_bmv);
    }

    // TVPbmt定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvp_bmt))
    {
        // 更新BMT报文内容
        int i;
        int tempera[128] = {0};
        unsigned int tempera_num = OpenChaoJi_evcc_hal_get_tempera_num(context->hal_handle);
        if (tempera_num > 128) tempera_num = 128;
        context->running_data.a->msg_bmt.tempera_num = tempera_num;
        OpenChaoJi_evcc_hal_get_tempera(context->hal_handle, tempera);
        for (i=0; i<tempera_num; i++)
        {
            context->running_data.a->msg_bmt.tempera[i] = (uint8_t)(50 + tempera[i]); // 动力蓄电池温度
        }

        // 发送BMT报文
        LOG_INFO("[%d]Charge S3 send bmt", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BMT, (uint8_t *)(&context->running_data.a->msg_bmt), sizeof(context->running_data.a->msg_bmt));

        // 重置TVPbmt
        LOG_INFO("[%d]Charge S3 reset timer TVPbmt", context->tag);
        OpenChaoJi_os_soft_timer_reset(&context->running_data.a->tvp_bmt);
    }

    // 接收充电机CCS报文
    if (context->running_data.a->msg_ccs_ok)
    {
        context->running_data.a->msg_ccs_ok = 0;

        LOG_DEBUG("[%d]Charge S3 ccs received", context->tag);

        // 重置TVOccs
        LOG_INFO("[%d]Charge S3 reset timer TVOccs", context->tag);
        OpenChaoJi_os_soft_timer_reset(&context->running_data.a->tvo_ccs);

        // 判断充电机是否恢复充电
        if (context->running_data.a->msg_ccs.state.bits.charging_permissible == OPENCHAOJI_GBT27930_A_PAUSE_STATUS_CHARGE) // 充电机允许充电
        {
            // 关闭TVOcsup
            LOG_INFO("[%d]Charge S3 stop timer TVOcsup", context->tag);
            OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_csup);

            // 判断车辆是否允许充电
            union OpenChaoJi_evcc_hal_batt_state state = OpenChaoJi_evcc_hal_get_batt_state(context->hal_handle);
            if (state.bits.charge_enable == OPENCHAOJI_GBT27930_A_PAUSE_STATUS_CHARGE) // 车辆允许充电
            {
                LOG_NOTICE("[%d]Charge S3 SECC Stop Suspend", context->tag);

                // 车辆允许充电, 进入S2
                LOG_NOTICE("[%d]Charge S3 To S2", context->tag);
                return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S2_ENERGY_TRANS;
            }
            else
            {
                LOG_NOTICE("[%d]Charge S3 SECC Stop Suspend & EVCC Start Suspend", context->tag);
                // 车辆暂停充电, 进入S4
                LOG_NOTICE("[%d]Charge S3 To S4", context->tag);
                return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S4_EV_SUSPEND;
            }
        }
    }

    // TVOccs定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvo_ccs))
    {
        LOG_ERR("[%d]Charge S3 ccs timeout", context->tag);

        // 发BEM报文, 此处只更新错误代码, 进入错误处理阶段后执行发送
        context->running_data.a->msg_bem.tout_code.bits.ccs = 0x01; // CCS超时

        // 进入S8
        LOG_ERR("[%d]Charge S3 To S8", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S8_ERROR;
    }

    // TVOcsup定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvo_csup))
    {
        LOG_ERR("[%d]Charge S3 SECC Suspend Timeout", context->tag);

        // 更新停机代码
        context->running_data.a->msg_bst.fault_code.bits.other = 0x01; // 车辆中止充电故障原因: 其他原因（充电机暂停充电超时）

        // 进入S5
        LOG_ERR("[%d]Charge S3 To S5", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S5_EV_STOP;
    }

    // 继续等待, 保持S3
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S3_SE_SUSPEND;
}

static void OpenChaoJi_gbt27930_a_evcc_prev_charge_s4_evcc_suspend(struct OpenChaoJi_evcc_context * context) {}
static void OpenChaoJi_gbt27930_a_evcc_post_charge_s4_evcc_suspend(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_charge_s4_evcc_suspend(struct OpenChaoJi_evcc_context * context)
{
    // TVPbcl定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvp_bcl))
    {
        // 向车查询车辆充电需求
        OpenChaoJi_evcc_app_get_charging_requirement(context, &context->running_data.a->charge.requirement_parameter);
        context->running_data.a->msg_bcl.target_voltage = context->running_data.a->charge.requirement_parameter.voltage;        // 车辆接口充电电压需求
        context->running_data.a->msg_bcl.target_current = 4000 - context->running_data.a->charge.requirement_parameter.current; // 车辆接口充电电流需求
        context->running_data.a->msg_bcl.charge_mode = context->running_data.a->charge.requirement_parameter.charge_mode;       // 充电模式

        // 发送BCL报文
        LOG_INFO("[%d]Charge S4 send bcl", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BCL, (uint8_t *)(&context->running_data.a->msg_bcl), sizeof(context->running_data.a->msg_bcl));

        // 重置TVPbcl
        LOG_INFO("[%d]Charge S4 reset timer TVPbcl", context->tag);
        OpenChaoJi_os_soft_timer_reset(&context->running_data.a->tvp_bcl);
    }

    // TVPbcs定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvp_bcs))
    {
        // 更新BCS报文内容
        context->running_data.a->msg_bcs.measured_voltage = OpenChaoJi_evcc_hal_get_measured_voltage(context->hal_handle); // 车辆接口当前电压测量值
        context->running_data.a->msg_bcs.measured_current = 4000 - OpenChaoJi_evcc_hal_get_measured_current(context->hal_handle); // 车辆接口当前电流测量值
        context->running_data.a->msg_bcs.soc = OpenChaoJi_evcc_hal_get_batt_soc(context->hal_handle) / 10; // 当前荷电状态, 注意分辨率
        context->running_data.a->msg_bcs.expected_time = OpenChaoJi_evcc_hal_get_expected_time(context->hal_handle); // 估算剩余充电时间
        struct OpenChaoJi_evcc_hal_batt_cellvolt temp = OpenChaoJi_evcc_hal_get_max_cellvolt(context->hal_handle);
        context->running_data.a->msg_bcs.max_cellvolt.bits.group = temp.group; // 最高单体蓄电池电压分组号
        context->running_data.a->msg_bcs.max_cellvolt.bits.value = temp.voltage; // 最高单体蓄电池电压值

        // 发送BCS报文
        LOG_INFO("[%d]Charge S4 send bcs", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BCS, (uint8_t *)(&context->running_data.a->msg_bcs), sizeof(context->running_data.a->msg_bcs));

        // 重置TVPbcs
        LOG_INFO("[%d]Charge S4 reset timer TVPbcs", context->tag);
        OpenChaoJi_os_soft_timer_reset(&context->running_data.a->tvp_bcs);
    }

    // TVPbsm定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvp_bsm))
    {
        // 更新BSM报文内容
        struct OpenChaoJi_evcc_hal_batt_cellvolt max_cellvolt = OpenChaoJi_evcc_hal_get_max_cellvolt(context->hal_handle);
        context->running_data.a->msg_bsm.max_cellvolt_id = max_cellvolt.id - 1; // 最高单体蓄电池电压所在编号
        struct OpenChaoJi_evcc_hal_batt_tempera max_tempera = OpenChaoJi_evcc_hal_get_max_tempera(context->hal_handle);
        context->running_data.a->msg_bsm.max_tempera = (uint8_t)(50 + max_tempera.tempera); // 当前单体蓄电池最高温度
        context->running_data.a->msg_bsm.max_tempera_id = max_tempera.id - 1; // 最高动力蓄电池温度检测点编号
        struct OpenChaoJi_evcc_hal_batt_tempera min_tempera = OpenChaoJi_evcc_hal_get_min_tempera(context->hal_handle);
        context->running_data.a->msg_bsm.min_tempera = (uint8_t)(50 + min_tempera.tempera); // 当前单体蓄电池最低温度
        context->running_data.a->msg_bsm.min_tempera_id = min_tempera.id - 1; // 最低动力蓄电池温度检测点编号
        union OpenChaoJi_evcc_hal_batt_state state = OpenChaoJi_evcc_hal_get_batt_state(context->hal_handle);
        context->running_data.a->msg_bsm.batt_state.all = state.all; // 电池状态及充电允许标识

        // 发送BSM报文
        LOG_INFO("[%d]Charge S4 send bsm", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BSM, (uint8_t *)(&context->running_data.a->msg_bsm), sizeof(context->running_data.a->msg_bsm));

        // 重置TVPbsm
        LOG_INFO("[%d]Charge S4 reset timer TVPbsm", context->tag);
        OpenChaoJi_os_soft_timer_reset(&context->running_data.a->tvp_bsm);
    }

    // TVPbmv定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvp_bmv))
    {
        // 更新BMV报文内容
        int i;
        unsigned char cellvolt_group[256] = {0};
        unsigned int cellvolt_value[256] = {0};
        unsigned int cellvolt_num = OpenChaoJi_evcc_hal_get_cellvolt_num(context->hal_handle); // 单体数量
        if (cellvolt_num > 256) cellvolt_num = 256;
        context->running_data.a->msg_bmv.cellvolt_num = cellvolt_num;
        OpenChaoJi_evcc_hal_get_cellvolt(context->hal_handle, cellvolt_group, cellvolt_value); // 单体信息
        for (i=0; i<cellvolt_num; i++)
        {
            context->running_data.a->msg_bmv.cellvolt[i].bits.group = cellvolt_group[i]; // 电池分组号
            context->running_data.a->msg_bmv.cellvolt[i].bits.value = cellvolt_value[i]; // 单体蓄电池电压值
        }

        // 发送BMV报文
        LOG_INFO("[%d]Charge S4 send bmv", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BMV, (uint8_t *)(&context->running_data.a->msg_bmv), sizeof(context->running_data.a->msg_bmv));

        // 重置TVPbmv
        LOG_INFO("[%d]Charge S4 reset timer TVPbmv", context->tag);
        OpenChaoJi_os_soft_timer_reset(&context->running_data.a->tvp_bmv);
    }

    // TVPbmt定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvp_bmt))
    {
        // 更新BMT报文内容
        int i;
        int tempera[128] = {0};
        unsigned int tempera_num = OpenChaoJi_evcc_hal_get_tempera_num(context->hal_handle);
        if (tempera_num > 128) tempera_num = 128;
        context->running_data.a->msg_bmt.tempera_num = tempera_num;
        OpenChaoJi_evcc_hal_get_tempera(context->hal_handle, tempera);
        for (i=0; i<tempera_num; i++)
        {
            context->running_data.a->msg_bmt.tempera[i] = (uint8_t)(50 + tempera[i]); // 动力蓄电池温度
        }

        // 发送BMT报文
        LOG_INFO("[%d]Charge S4 send bmt", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BMT, (uint8_t *)(&context->running_data.a->msg_bmt), sizeof(context->running_data.a->msg_bmt));

        // 重置TVPbmt
        LOG_INFO("[%d]Charge S4 reset timer TVPbmt", context->tag);
        OpenChaoJi_os_soft_timer_reset(&context->running_data.a->tvp_bmt);
    }

    // 接收充电机CCS报文
    if (context->running_data.a->msg_ccs_ok)
    {
        context->running_data.a->msg_ccs_ok = 0;

        LOG_DEBUG("[%d]Charge S4 ccs received", context->tag);

        // 重置TVOccs
        LOG_INFO("[%d]Charge S4 reset timer TVOccs", context->tag);
        OpenChaoJi_os_soft_timer_reset(&context->running_data.a->tvo_ccs);

        // 判断充电机是否允许充电
        if (context->running_data.a->msg_ccs.state.bits.charging_permissible == OPENCHAOJI_GBT27930_A_PAUSE_STATUS_PAUSE) // 暂停充电
        {
            LOG_NOTICE("[%d]Charge S4 SECC Start Suspend", context->tag);

            // 打开TVOcsup
            LOG_INFO("[%d]Charge S4 start timer TVOcsup", context->tag);
            OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvo_csup, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVOCSUP);

            // 充电机暂停充电, 进入S3
            LOG_NOTICE("[%d]Charge S4 To S3", context->tag);
            return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S3_SE_SUSPEND;
        }
    }

    // TVOccs定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvo_ccs))
    {
        LOG_ERR("[%d]Charge S4 ccs timeout", context->tag);

        // 发BEM报文, 此处只更新错误代码, 进入错误处理阶段后执行发送
        context->running_data.a->msg_bem.tout_code.bits.ccs = 0x01; // CCS超时

        // 进入S8
        LOG_ERR("[%d]Charge S4 To S8", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S8_ERROR;
    }

    // 判断车辆是否恢复充电
    union OpenChaoJi_evcc_hal_batt_state state = OpenChaoJi_evcc_hal_get_batt_state(context->hal_handle);
    if (state.bits.charge_enable == OPENCHAOJI_GBT27930_A_PAUSE_STATUS_CHARGE) // 允许充电
    {
        LOG_NOTICE("[%d]Charge S4 EVCC Stop Suspend", context->tag);

        // 车辆恢复充电, 进入S2
        LOG_NOTICE("[%d]Charge S4 To S2", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S2_ENERGY_TRANS;
    }

    // 继续等待, 保持S4
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S4_EV_SUSPEND;
}

static void OpenChaoJi_gbt27930_a_evcc_prev_charge_s5_evcc_stop(struct OpenChaoJi_evcc_context * context)
{
    context->running_data.a->msg_cst_ok = 0;
}
static void OpenChaoJi_gbt27930_a_evcc_post_charge_s5_evcc_stop(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_charge_s5_evcc_stop(struct OpenChaoJi_evcc_context * context)
{
    // EVCC主动中止, 首次发送BST
    if (!context->running_data.a->charge.send_bst)
    {
        context->running_data.a->charge.send_bst = 1;

        LOG_INFO("[%d]Charge S5 stop all invalid timer", context->tag);

        // 关闭TVPbcl
        LOG_INFO("[%d]Charge S5 stop timer TVPbcl", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bcl);

        // 关闭TVPbcs
        LOG_INFO("[%d]Charge S5 stop timer TVPbcs", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bcs);

        // 关闭TVPbsm
        LOG_INFO("[%d]Charge S5 stop timer TVPbsm", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bsm);

        // 关闭TVPbmv
        LOG_INFO("[%d]Charge S5 stop timer TVPbmv", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bmv);

        // 关闭TVPbmt
        LOG_INFO("[%d]Charge S5 stop timer TVPbmt", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bmt);

        // 关闭TVOccs
        LOG_INFO("[%d]Charge S5 stop timer TVOccs", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_ccs);

        // 发送BST报文 (充电阶段车辆主动停止, 会直接跳转到S5进行停机交互)
        LOG_INFO("[%d]Charge S5 send bst", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BST, (uint8_t *)(&context->running_data.a->msg_bst), sizeof(context->running_data.a->msg_bst));

        // 打开TVPbst
        LOG_INFO("[%d]Charge S5 start timer TVPbst", context->tag);
        OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvp_bst, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVPBST);

        // 打开TVOcst
        LOG_INFO("[%d]Charge S5 start timer TVOcst", context->tag);
        OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvo_cst, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVOCST);

        // 打开TVOcsd
        LOG_INFO("[%d]Charge S5 start timer TVOcsd", context->tag);
        OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvo_csd, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVOCSD);
    }

    // TVPbst定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvp_bst))
    {
        // 发送BST报文
        LOG_INFO("[%d]Charge S5 send bst", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BST, (uint8_t *)(&context->running_data.a->msg_bst), sizeof(context->running_data.a->msg_bst));

        // 重置TVPbst
        LOG_INFO("[%d]Charge S5 reset timer TVPbst", context->tag);
        OpenChaoJi_os_soft_timer_reset(&context->running_data.a->tvp_bst);
    }

    // 接收充电机CST报文
    if (context->running_data.a->msg_cst_ok)
    {
        LOG_NOTICE("[%d]Charge S5 cst received", context->tag);

        // 关闭TVPbst
        LOG_INFO("[%d]Charge S5 stop timer TVPbst", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bst);

        // 进入S7
        LOG_NOTICE("[%d]Charge S5 To S7", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S7_STOPPED;
    }

    // TVOcst定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvo_cst))
    {
        LOG_ERR("[%d]Charge S5 cst timeout", context->tag);

        // 关闭TVPbst
        LOG_INFO("[%d]Charge S5 stop timer TVPbst", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bst);

        // 发BEM报文, 此处只更新错误代码, 进入错误处理阶段后执行发送
        context->running_data.a->msg_bem.tout_code.bits.cst = 0x01; // CST超时

        // 进入S8
        LOG_ERR("[%d]Charge S5 To S8", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S8_ERROR;
    }

    // 继续等待, 保持S5
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S5_EV_STOP;
}

static void OpenChaoJi_gbt27930_a_evcc_prev_charge_s6_secc_stop(struct OpenChaoJi_evcc_context * context)
{
    context->running_data.a->msg_cst_ok = 0;
}
static void OpenChaoJi_gbt27930_a_evcc_post_charge_s6_secc_stop(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_charge_s6_secc_stop(struct OpenChaoJi_evcc_context * context)
{
    // SECC主动中止, 首次发送BST
    if (!context->running_data.a->charge.send_bst)
    {
        context->running_data.a->charge.send_bst = 1;

        LOG_INFO("[%d]Charge S6 stop all invalid timer", context->tag);

        // 关闭TVPbcl
        LOG_INFO("[%d]Charge S6 stop timer TVPbcl", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bcl);

        // 关闭TVPbcs
        LOG_INFO("[%d]Charge S6 stop timer TVPbcs", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bcs);

        // 关闭TVPbsm
        LOG_INFO("[%d]Charge S6 stop timer TVPbsm", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bsm);

        // 关闭TVPbmv
        LOG_INFO("[%d]Charge S6 stop timer TVPbmv", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bmv);

        // 关闭TVPbmt
        LOG_INFO("[%d]Charge S6 stop timer TVPbmt", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bmt);

        // 关闭TVOccs
        LOG_INFO("[%d]Charge S6 stop timer TVOccs", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_ccs);

        // 发送BST报文 (各阶段收到CST, 会直接跳转到S6进行停机交互)
        LOG_INFO("[%d]Charge S6 send bst", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BST, (uint8_t *)(&context->running_data.a->msg_bst), sizeof(context->running_data.a->msg_bst));

        // 首次发送
        context->running_data.a->charge.bst_notice_delay = 1;

        // 打开TVPbst
        LOG_INFO("[%d]Charge S6 start timer TVPbst", context->tag);
        OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvp_bst, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVPBST);

        // 打开TVOcsd
        LOG_INFO("[%d]Charge S6 start timer TVOcsd", context->tag);
        OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvo_csd, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVOCSD);
    }

    // TVPbst定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvp_bst))
    {
        // 发送BST报文
        LOG_INFO("[%d]Charge S6 send bst", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BST, (uint8_t *)(&context->running_data.a->msg_bst), sizeof(context->running_data.a->msg_bst));

        // 重置TVPbst
        LOG_INFO("[%d]Charge S6 reset timer TVPbst", context->tag);
        OpenChaoJi_os_soft_timer_reset(&context->running_data.a->tvp_bst);

        // 发送BST次数累加
        context->running_data.a->charge.bst_notice_delay++;
    }

    // 发送5-10帧BST后中止
    if (context->running_data.a->charge.bst_notice_delay >= 10)
    {
        LOG_INFO("[%d]Charge S6 send bst finished", context->tag);

        // 关闭TVPbst
        LOG_INFO("[%d]Charge S6 stop timer TVPbst", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bst);

        // 进入S7
        LOG_NOTICE("[%d]Charge S6 To S7", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S7_STOPPED;
    }

    // 继续等待, 保持S6
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S6_SE_STOP;
}

static void OpenChaoJi_gbt27930_a_evcc_prev_charge_s7_stopped(struct OpenChaoJi_evcc_context * context) {}
static void OpenChaoJi_gbt27930_a_evcc_post_charge_s7_stopped(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_charge_s7_stopped(struct OpenChaoJi_evcc_context * context)
{
    // 进入充电结束阶段
    LOG_NOTICE("[%d]Charge S7 To End S0", context->tag);
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_END_S0_INIT;
}

static void OpenChaoJi_gbt27930_a_evcc_prev_charge_s8_error(struct OpenChaoJi_evcc_context * context) {}
static void OpenChaoJi_gbt27930_a_evcc_post_charge_s8_error(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_charge_s8_error(struct OpenChaoJi_evcc_context * context)
{
    LOG_INFO("[%d]Charge S8 stop all invalid timer", context->tag);

    // 关闭TVPbcl
    LOG_INFO("[%d]Charge S8 stop timer TVPbcl", context->tag);
    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bcl);

    // 关闭TVPbcs
    LOG_INFO("[%d]Charge S8 stop timer TVPbcs", context->tag);
    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bcs);

    // 关闭TVPbsm
    LOG_INFO("[%d]Charge S8 stop timer TVPbsm", context->tag);
    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bsm);

    // 关闭TVPbmv
    LOG_INFO("[%d]Charge S8 stop timer TVPbmv", context->tag);
    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bmv);

    // 关闭TVPbmt
    LOG_INFO("[%d]Charge S8 stop timer TVPbmt", context->tag);
    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bmt);

    // 关闭TVOccs
    LOG_INFO("[%d]Charge S8 stop timer TVOccs", context->tag);
    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_ccs);

    // 关闭TVOcsup
    LOG_INFO("[%d]Charge S8 stop timer TVOcsup", context->tag);
    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_csup);

    // 进入错误处理阶段
    LOG_ERR("[%d]Charge S8 To Error S0", context->tag);
    context->running_data.a->stop_ticks = OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVO_STOP_TIMEOUT;
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_ERROR_S0_INIT;
}

const struct OpenChaoJi_evcc_module_status c_sytem_a_evcc_status_array_charge[OPENCHAOJI_GBT27930_A_EVCC_STATUS_CHARGE_NUM] = {
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S0_INIT,
        .name = "Charge.S0.Init",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_charge_s0_init,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_charge_s0_init,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_charge_s0_init,
    },
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S1_WAIT_CCS,
        .name = "Charge.S1.Wait_CCS",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_charge_s1_wait_ccs,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_charge_s1_wait_ccs,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_charge_s1_wait_ccs,
    },
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S2_ENERGY_TRANS,
        .name = "Charge.S2.Energy_Trans",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_charge_s2_energy_trans,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_charge_s2_energy_trans,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_charge_s2_energy_trans,
    },
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S3_SE_SUSPEND,
        .name = "Charge.S3.SECC_Suspend",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_charge_s3_secc_suspend,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_charge_s3_secc_suspend,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_charge_s3_secc_suspend,
    },
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S4_EV_SUSPEND,
        .name = "Charge.S4.EVCC_Suspend",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_charge_s4_evcc_suspend,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_charge_s4_evcc_suspend,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_charge_s4_evcc_suspend,
    },
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S5_EV_STOP,
        .name = "Charge.S5.EVCC_Stop",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_charge_s5_evcc_stop,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_charge_s5_evcc_stop,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_charge_s5_evcc_stop,
    },
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S6_SE_STOP,
        .name = "Charge.S6.SECC_Stop",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_charge_s6_secc_stop,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_charge_s6_secc_stop,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_charge_s6_secc_stop,
    },
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S7_STOPPED,
        .name = "Charge.S7.Stopped",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_charge_s7_stopped,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_charge_s7_stopped,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_charge_s7_stopped,
    },
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S8_ERROR,
        .name = "Charge.S8.Error",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_charge_s8_error,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_charge_s8_error,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_charge_s8_error,
    },
};

const struct OpenChaoJi_evcc_module c_gbt27930_a_evcc_module_charge =
{
    .module_id = OPENCHAOJI_GBT27930_A_MODULE_CHARGE,
    .name = "Charge",
    .status_array = c_sytem_a_evcc_status_array_charge,
    .status_array_len = OPENCHAOJI_GBT27930_A_EVCC_STATUS_CHARGE_NUM,
};

/* 充电结束 */

static void OpenChaoJi_gbt27930_a_evcc_prev_end_s0_init(struct OpenChaoJi_evcc_context * context)
{
    LOG_NOTICE("[%d]End Status Start", context->tag);
    LOG_NOTICE("[%d]End S0 init", context->tag);
}
static void OpenChaoJi_gbt27930_a_evcc_post_end_s0_init(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_end_s0_init(struct OpenChaoJi_evcc_context * context)
{
    context->running_data.a->msg_bsd.end_soc = OpenChaoJi_evcc_hal_get_batt_soc(context->hal_handle) / 10; // 中止荷电状态SOC, 注意分辨率
    struct OpenChaoJi_evcc_hal_batt_cellvolt min_cellvolt = OpenChaoJi_evcc_hal_get_min_cellvolt(context->hal_handle);
    context->running_data.a->msg_bsd.min_cellvolt = min_cellvolt.voltage; // 单体蓄电池最低电压
    struct OpenChaoJi_evcc_hal_batt_cellvolt max_cellvolt = OpenChaoJi_evcc_hal_get_max_cellvolt(context->hal_handle);
    context->running_data.a->msg_bsd.max_cellvolt = max_cellvolt.voltage; // 单体蓄电池最高电压
    struct OpenChaoJi_evcc_hal_batt_tempera min_tempera = OpenChaoJi_evcc_hal_get_min_tempera(context->hal_handle);
    context->running_data.a->msg_bsd.min_tempera = (uint8_t)(50 + min_tempera.tempera); // 动力蓄电池最低温度
    struct OpenChaoJi_evcc_hal_batt_tempera max_tempera = OpenChaoJi_evcc_hal_get_max_tempera(context->hal_handle);
    context->running_data.a->msg_bsd.max_tempera = (uint8_t)(50 + max_tempera.tempera); // 动力蓄电池最高温度

    // 发送BSD报文
    LOG_INFO("[%d]End S0 send bsd", context->tag);
    OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BSD, (uint8_t *)(&context->running_data.a->msg_bsd), sizeof(context->running_data.a->msg_bsd));

    // 打开TVPbsd
    LOG_INFO("[%d]End S0 start timer TVPbsd", context->tag);
    OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvp_bsd, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVPBSD);

    // 进入S1
    LOG_NOTICE("[%d]End S0 To S1", context->tag);
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_END_S1_STATISTICS;
}

static void OpenChaoJi_gbt27930_a_evcc_prev_end_s1_wait_csd(struct OpenChaoJi_evcc_context * context)
{
    context->running_data.a->msg_csd_ok = 0;
}
static void OpenChaoJi_gbt27930_a_evcc_post_end_s1_wait_csd(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_end_s1_wait_csd(struct OpenChaoJi_evcc_context * context)
{
    // TVPbsd定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvp_bsd))
    {
        // 发送BSD报文
        LOG_INFO("[%d]End S1 send bsd", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BSD, (uint8_t *)(&context->running_data.a->msg_bsd), sizeof(context->running_data.a->msg_bsd));

        // 重置TVPbsd
        LOG_INFO("[%d]End S1 reset timer TVPbsd", context->tag);
        OpenChaoJi_os_soft_timer_reset(&context->running_data.a->tvp_bsd);
    }

    // 接收充电机CSD报文
    if (context->running_data.a->msg_csd_ok)
    {
        LOG_NOTICE("[%d]End S1 csd received", context->tag);

        // 关闭TVPbsd
        LOG_INFO("[%d]End S1 stop timer TVPbsd", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bsd);

        // 关闭TVOcsd
        LOG_INFO("[%d]End S1 stop timer TVOcsd", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_csd);

        // 进入S2
        LOG_NOTICE("[%d]End S1 To S2", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_END_S2_FINISHED;
    }

    // TVOcsd定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvo_csd))
    {
        LOG_ERR("[%d]End S1 csd timeout", context->tag);

        // 关闭TVPbsd
        LOG_INFO("[%d]End S1 stop timer TVPbsd", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bsd);

        // 发BEM报文, 此处只更新错误代码, 进入错误处理阶段后执行发送
        context->running_data.a->msg_bem.tout_code.bits.csd = 0x01; // CSD超时

        // 进入S8
        LOG_ERR("[%d]End S1 To S3", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_END_S3_ERROR;
    }

    // 未收到, 未超时, 继续等待, 保持S1
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_END_S1_STATISTICS;
}

static void OpenChaoJi_gbt27930_a_evcc_prev_end_s2_finished(struct OpenChaoJi_evcc_context * context) {}
static void OpenChaoJi_gbt27930_a_evcc_post_end_s2_finished(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_end_s2_finished(struct OpenChaoJi_evcc_context * context)
{
    if (context->running_data.a->stop_status >= OPENCHAOJI_GBT27930_A_EVCC_STOPPING_STATUS_FINISHED) // 停机完成
    {
        // 复位充电启动标识
        context->app_permit_charge = 0;

        LOG_NOTICE("[%d]End Staus Exit", context->tag);

        // 退出充电
        LOG_NOTICE("[%d]End S2 Return to Idle", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_IDLE_S0_IDLE;
    }

    // 等待停机完成
    LOG_DEBUG("[%d]End S2 stopping", context->tag);
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_END_S2_FINISHED;
}

static void OpenChaoJi_gbt27930_a_evcc_prev_end_s3_error(struct OpenChaoJi_evcc_context * context) {}
static void OpenChaoJi_gbt27930_a_evcc_post_end_s3_error(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_end_s3_error(struct OpenChaoJi_evcc_context * context)
{
    // 进入错误处理阶段
    LOG_ERR("[%d]End S3 To Error S0", context->tag);
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_ERROR_S0_INIT;
}

const struct OpenChaoJi_evcc_module_status c_sytem_a_evcc_status_array_end[OPENCHAOJI_GBT27930_A_EVCC_STATUS_END_NUM] = {
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_END_S0_INIT,
        .name = "End.S0.Init",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_end_s0_init,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_end_s0_init,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_end_s0_init,
    },
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_END_S1_STATISTICS,
        .name = "End.S1.Wait_CSD",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_end_s1_wait_csd,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_end_s1_wait_csd,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_end_s1_wait_csd,
    },
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_END_S2_FINISHED,
        .name = "End.S2.Finished",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_end_s2_finished,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_end_s2_finished,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_end_s2_finished,
    },
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_END_S3_ERROR,
        .name = "End.S3.Error",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_end_s3_error,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_end_s3_error,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_end_s3_error,
    },
};

const struct OpenChaoJi_evcc_module c_gbt27930_a_evcc_module_end =
{
    .module_id = OPENCHAOJI_GBT27930_A_MODULE_END,
    .name = "End",
    .status_array = c_sytem_a_evcc_status_array_end,
    .status_array_len = OPENCHAOJI_GBT27930_A_EVCC_STATUS_END_NUM,
};

/* 错误处理 */

static void OpenChaoJi_gbt27930_a_evcc_prev_error_s0_init(struct OpenChaoJi_evcc_context * context)
{
    LOG_NOTICE("[%d]Error Staus Start", context->tag);
    LOG_NOTICE("[%d]Error S0 init", context->tag);
}
static void OpenChaoJi_gbt27930_a_evcc_post_error_s0_init(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_error_s0_init(struct OpenChaoJi_evcc_context * context)
{
    if (context->running_data.a->msg_bem.tout_code.all & (~0xFCF0F0F0)) // 车辆检测到通信超时错误
    {
        LOG_NOTICE("[%d]Error S0 bem mode", context->tag);

        // 发送BEM报文
        LOG_INFO("[%d]Error S0 send bem", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BEM, (uint8_t *)(&context->running_data.a->msg_bem), sizeof(context->running_data.a->msg_bem));

        // 打开TVPbem
        LOG_INFO("[%d]Error S0 start timer TVPbem", context->tag);
        OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvp_bem, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVPBEM);

        // 打开TVObep (错误处理超时定时器)
        LOG_INFO("[%d]Error S0 start timer TVObep", context->tag);
        OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvo_bep, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVOBEP);

        // 打开TVOcrm
        LOG_INFO("[%d]Error S0 start timer TVOcrm", context->tag);
        OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvo_crm, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVOCRM);

        // 进入S2
        LOG_NOTICE("[%d]Error S0 To S2", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_ERROR_S2_BEM;
    }
    else // 接收到充电机CEM报文(充电机检测到超时)
    {
        LOG_NOTICE("[%d]Error S0 cem mode", context->tag);

        // 打开TVObep
        LOG_INFO("[%d]Error S0 start timer TVObep", context->tag);
        OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvo_bep, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVOBEP);

        // 打开TVOcrm (自收到CEM报文起30s)
        LOG_INFO("[%d]Error S0 start timer TVOcrm", context->tag);
        OpenChaoJi_os_soft_timer_start(&context->running_data.a->tvo_crm, OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVOCRM);

        // 进入S1
        LOG_NOTICE("[%d]Error S0 To S1", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_ERROR_S1_CEM;
    }
}

static void OpenChaoJi_gbt27930_a_evcc_prev_error_s1_cem(struct OpenChaoJi_evcc_context * context) {}
static void OpenChaoJi_gbt27930_a_evcc_post_error_s1_cem(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_error_s1_cem(struct OpenChaoJi_evcc_context * context)
{
    // 错误处理完成状态判断
    if (context->running_data.a->stop_status == OPENCHAOJI_GBT27930_A_EVCC_STOPPING_STATUS_FINISHED) // 电流降低至5A及以下后断开C5C6, 且继电器外侧电压降到60V以下
    {
        LOG_NOTICE("[%d]Error S1 handling result is ok", context->tag);

        // 关闭TVObep (错误处理超时定时器)
        LOG_INFO("[%d]Error S1 stop timer TVObep", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_bep);

        // 进入S3
        LOG_NOTICE("[%d]Error S1 To S3", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_ERROR_S3_CHECK;
    }

    // TVObep定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvo_bep))
    {
        LOG_ERR("[%d]Error S1 handling timeout", context->tag);

        // 关闭TVOcrm
        LOG_INFO("[%d]Error S1 stop timer TVOcrm", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_crm);

        // 断开C5 C6（如未断）
        LOG_NOTICE("[%d]Error S1 cut off C5 C6 (confirm)", context->tag);
        OpenChaoJi_evcc_hal_gbt_close_dc_relay(context->hal_handle, 0);

        // 进入S6
        LOG_ERR("[%d]Error S1 To S6", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_ERROR_S6_FINISHED;
    }

    // 未超时, 继续等待
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_ERROR_S1_CEM;
}

static void OpenChaoJi_gbt27930_a_evcc_prev_error_s2_bem(struct OpenChaoJi_evcc_context * context) {}
static void OpenChaoJi_gbt27930_a_evcc_post_error_s2_bem(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_error_s2_bem(struct OpenChaoJi_evcc_context * context)
{
    // TVPbem定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvp_bem))
    {
        // 发送BEM报文
        LOG_INFO("[%d]Error S2 send bem", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BEM, (uint8_t *)(&context->running_data.a->msg_bem), sizeof(context->running_data.a->msg_bem));

        // 重置TVPbem
        LOG_INFO("[%d]Error S2 reset timer TVPbem", context->tag);
        OpenChaoJi_os_soft_timer_reset(&context->running_data.a->tvp_bem);
    }

    // 错误处理完成状态判断
    if (context->running_data.a->stop_status == OPENCHAOJI_GBT27930_A_EVCC_STOPPING_STATUS_FINISHED) // 电流降低至5A及以下后断开C5C6, 且继电器外侧电压降到60V以下
    {
        LOG_NOTICE("[%d]Error S2 handling result is ok", context->tag);

        // 关闭TVObep
        LOG_INFO("[%d]Error S2 stop timer TVObep", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_bep);

        // 进入S3
        LOG_NOTICE("[%d]Error S2 To S3", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_ERROR_S3_CHECK;
    }

    // TVObep定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvo_bep))
    {
        LOG_ERR("[%d]Error S2 handling timeout", context->tag);

        // 关闭TVPbem
        LOG_INFO("[%d]Error S2 stop timer TVPbem", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bem);

        // 关闭TVOcrm
        LOG_INFO("[%d]Error S2 stop timer TVOcrm", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_crm);

        // 断开C5 C6（如未断）
        LOG_NOTICE("[%d]Error S2 cut off C5 C6 (confirm)", context->tag);
        OpenChaoJi_evcc_hal_gbt_close_dc_relay(context->hal_handle, 0);

        // 进入S6
        LOG_ERR("[%d]Error S2 To S6", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_ERROR_S6_FINISHED;
    }

    // 未超时, 继续等待, 保持S2
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_ERROR_S2_BEM;
}

static void OpenChaoJi_gbt27930_a_evcc_prev_error_s3_check(struct OpenChaoJi_evcc_context * context) {}
static void OpenChaoJi_gbt27930_a_evcc_post_error_s3_check(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_error_s3_check(struct OpenChaoJi_evcc_context * context)
{
    LOG_INFO("[%d]Error S3 check for reconnect", context->tag);

    // 重连条件 BCP BRO BCL BCS + CML CRO CCS
    if (context->running_data.a->msg_cem.tout_code.bits.timeout_bcp == 1 || \
        context->running_data.a->msg_cem.tout_code.bits.timeout_bro == 1 || \
        context->running_data.a->msg_cem.tout_code.bits.timeout_bcl == 1 || \
        context->running_data.a->msg_cem.tout_code.bits.timeout_bcs == 1 || \
        context->running_data.a->msg_bem.tout_code.bits.cml == 1 || \
        context->running_data.a->msg_bem.tout_code.bits.cro == 1 || \
        context->running_data.a->msg_bem.tout_code.bits.ccs == 1 )
    {
        LOG_NOTICE("[%d]Error S3 ready to reconnect", context->tag);
        context->running_data.a->reconnect_flag = 1;

        // 进入S4
        LOG_NOTICE("[%d]Error S3 To S4", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_ERROR_S4_WAIT_CRM;
    }

    LOG_NOTICE("[%d]Error S3 Communicate reconnect cancel", context->tag);

    // 关闭TVPbem
    LOG_INFO("[%d]Error S3 stop timer TVPbem", context->tag);
    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bem);

    // 关闭TVOcrm
    LOG_INFO("[%d]Error S3 stop timer TVOcrm", context->tag);
    OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_crm);

    // 进入S6
    LOG_NOTICE("[%d]Error S3 To S6", context->tag);
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_ERROR_S6_FINISHED;
}

static void OpenChaoJi_gbt27930_a_evcc_prev_error_s4_wait_crm(struct OpenChaoJi_evcc_context * context)
{
    context->running_data.a->msg_crm_ok = 0;
}
static void OpenChaoJi_gbt27930_a_evcc_post_error_s4_wait_crm(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_error_s4_wait_crm(struct OpenChaoJi_evcc_context * context)
{
    // TVPbem定时器到 - 车辆检测到通信超时错误, 周期发送BEM
    if ((context->running_data.a->msg_bem.tout_code.all & (~0xFCF0F0F0)) && \
        OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvp_bem))
    {
        // 发送BEM报文
        LOG_INFO("[%d]Error S4 send bem", context->tag);
        OpenChaoJi_gbt27930_a_evcc_send_normal(context, OPENCHAOJI_GBT27930_A_PID_TAG_BEM, (uint8_t *)(&context->running_data.a->msg_bem), sizeof(context->running_data.a->msg_bem));

        // 重置TVPbem
        LOG_INFO("[%d]Error S4 reset timer TVPbem", context->tag);
        OpenChaoJi_os_soft_timer_reset(&context->running_data.a->tvp_bem);
    }

    // 接收充电机CRM报文
    if (context->running_data.a->msg_crm_ok && \
        context->running_data.a->msg_crm.recognition_result == OPENCHAOJI_GBT27930_A_RECOGNIZE_TYPE_NOT_RECOGNIZED)
    {
        LOG_NOTICE("[%d]Error S4 crm_00 received", context->tag);

        // 关闭TVPbem
        LOG_INFO("[%d]Error S4 stop timer TVPbem", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bem);

        // 关闭TVOcrm
        LOG_INFO("[%d]Error S4 stop timer TVOcrm", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvo_crm);

        // 进入S5
        LOG_NOTICE("[%d]Error S4 To S5", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_ERROR_S5_RETRY;
    }

    // TVOcrm定时器到
    if (OpenChaoJi_os_soft_timer_is_timeout(&context->running_data.a->tvo_crm))
    {
        LOG_ERR("[%d]Error S4 crm_00 timeout", context->tag);

        // 关闭TVPbem
        LOG_INFO("[%d]Error S4 stop timer TVPbem", context->tag);
        OpenChaoJi_os_soft_timer_stop(&context->running_data.a->tvp_bem);

        // 进入S6
        LOG_ERR("[%d]Error S4 To S6", context->tag);
        return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_ERROR_S6_FINISHED;
    }

    // 未收到, 未超时, 继续等待, 保持S4
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_ERROR_S4_WAIT_CRM;
}

static void OpenChaoJi_gbt27930_a_evcc_prev_error_s5_retry(struct OpenChaoJi_evcc_context * context) {}
static void OpenChaoJi_gbt27930_a_evcc_post_error_s5_retry(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_error_s5_retry(struct OpenChaoJi_evcc_context * context)
{
    LOG_NOTICE("[%d]Reconnect Start", context->tag);
    OpenChaoJi_gbt27930_a_evcc_running_data_timer_reset(context);

    // 进入充电握手阶段
    LOG_NOTICE("[%d]Error S5 To Handshake S0", context->tag);
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_HANDSHAKE_S0_INIT;
}

static void OpenChaoJi_gbt27930_a_evcc_prev_error_s6_finished(struct OpenChaoJi_evcc_context * context) {}
static void OpenChaoJi_gbt27930_a_evcc_post_error_s6_finished(struct OpenChaoJi_evcc_context * context) {}
static int  OpenChaoJi_gbt27930_a_evcc_loop_error_s6_finished(struct OpenChaoJi_evcc_context * context)
{
    // 复位充电启动标识
    context->app_permit_charge = 0;

    LOG_NOTICE("[%d]Error Status Exit", context->tag);

    // 退出充电
    LOG_NOTICE("[%d]Error S6 Return to Idle", context->tag);
    return OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_IDLE_S0_IDLE;
}

const struct OpenChaoJi_evcc_module_status c_sytem_a_evcc_status_array_error[OPENCHAOJI_GBT27930_A_EVCC_STATUS_ERROR_NUM] = {
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_ERROR_S0_INIT,
        .name = "Error.S0.Init",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_error_s0_init,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_error_s0_init,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_error_s0_init,
    },
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_ERROR_S1_CEM,
        .name = "Error.S1.CEM",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_error_s1_cem,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_error_s1_cem,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_error_s1_cem,
    },
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_ERROR_S2_BEM,
        .name = "Error.S2.BEM",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_error_s2_bem,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_error_s2_bem,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_error_s2_bem,
    },
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_ERROR_S3_CHECK,
        .name = "Error.S3.Check",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_error_s3_check,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_error_s3_check,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_error_s3_check,
    },
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_ERROR_S4_WAIT_CRM,
        .name = "Error.S4.Wait_CRM",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_error_s4_wait_crm,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_error_s4_wait_crm,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_error_s4_wait_crm,
    },
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_ERROR_S5_RETRY,
        .name = "Error.S5.Retry",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_error_s5_retry,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_error_s5_retry,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_error_s5_retry,
    },
    {
        .module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_ERROR_S6_FINISHED,
        .name = "Error.S6.Finished",

        .prev_func = OpenChaoJi_gbt27930_a_evcc_prev_error_s6_finished,
        .post_func = OpenChaoJi_gbt27930_a_evcc_post_error_s6_finished,
        .loop_func = OpenChaoJi_gbt27930_a_evcc_loop_error_s6_finished,
    },
};

const struct OpenChaoJi_evcc_module c_gbt27930_a_evcc_module_error =
{
    .module_id = OPENCHAOJI_GBT27930_A_MODULE_ERROR,
    .name = "Error",
    .status_array = c_sytem_a_evcc_status_array_error,
    .status_array_len = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ERROR_NUM,
};

/**
 * 通用子模块处理, 即跨越一般功能模块的一些全局功能的处理. 例如链路检测, 连接检测等
 * 由于连接检测需要快速响应, 厂家底层实现时可以考虑通过中断等方式触发后立即调用service方法来触发处理流程, 而不必等到定时处理
*/

static int OpenChaoJi_gbt27930_a_evcc_sub_module_func(struct OpenChaoJi_evcc_context * context)
{
    // TODO: 各种错误处理, 参考18487和27930
    if (context->current_module_status_id > OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_IDLE_S0_IDLE && \
        context->current_module_status_id < OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S5_EV_STOP)
    {
        if (OpenChaoJi_evcc_utility_session_is_connected(context->context_session) == OPENCHAOJI_EVCC_UTILITY_SESSION_CONNECT_STATUS_DISCONNECTED)
        {
            // 没有session_start暂时不判断
            // LOG_ERR("[%d]Lost Connection", context->tag);
            // return OpenChaoJi_gbt27930_a_evcc_stop_failed(context, OPENCHAOJI_GBT27930_A_END_CODE_EVCC_FAULT, OPENCHAOJI_GBT27930_A_END_REASON_EVCC_FAULT_OTHER);
        }

        struct OpenChaoJi_evcc_hal_samp samp_value;
        OpenChaoJi_evcc_hal_sampling_value(context->hal_handle, &samp_value);

        // GB/T 18487.1 B.4.6 达到所需求的SOC目标值、达到总电压的设定值、达到单体电压的设定值
        if (!context->app_permit_charge)
        {
            // TODO: 需要知道APP中止原因明细
            LOG_ERR("[%d]AppStop", context->tag);

            // 正常中止
            context->running_data.a->stop_ticks = OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVO_STOP_NORMAL(samp_value.current);
            // 故障中止
            // context->running_data.a->stop_ticks = OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVO_STOP_FAULT;

            return OpenChaoJi_gbt27930_a_evcc_stop_normal(context, OPENCHAOJI_GBT27930_A_END_CODE_EVCC_NORMAL, OPENCHAOJI_GBT27930_A_END_REASON_EVCC_NORMAL_OTHER);
        }

        // GB/T 18487.1 B.4.6 充电机主动中止
        if (context->running_data.a->msg_cst_ok)
        {
            LOG_ERR("[%d]SECC Stop", context->tag);

            if (context->running_data.a->msg_cst.stop_code.bits.fault_suspends)
                context->running_data.a->stop_ticks = OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVO_STOP_FAULT;
            else
                context->running_data.a->stop_ticks = OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVO_STOP_NORMAL(samp_value.current);

            return OpenChaoJi_gbt27930_a_evcc_stop_normal(context, OPENCHAOJI_GBT27930_A_END_CODE_EVCC_NORMAL, OPENCHAOJI_GBT27930_A_END_REASON_EVCC_NORMAL_CST);
        }

        if (context->current_module_status_id > OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_TRIGGER_S0_CONNECT_CONFIRM)
        {
            // GB/T 18487.1 B.4.7.3 检测点2电压异常
            if (!OpenChaoJi_evcc_utility_pilot_is_secc_connected(context->context_pilot))
            {
                LOG_ERR("[%d]CC2 Error", context->tag);
                context->running_data.a->stop_ticks = OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVO_STOP_FAULT;
                return OpenChaoJi_gbt27930_a_evcc_stop_failed(context, OPENCHAOJI_GBT27930_A_END_CODE_EVCC_FAULT, OPENCHAOJI_GBT27930_A_END_REASON_EVCC_FAULT_CC2_VOLTAGE);
            }
        #if 0
            // GB/T 18487.1 B.4.7.6 车辆接口处充电电压超过车辆最高允许充电总电压+15V (由充电机检测, 待确认是否保留)
            if (context->running_data.a->msg_bcs.measured_voltage > (context->running_data.a->msg_bcp.allow_voltage + 150))
            {
                LOG_ERR("[%d]SECC Volatge Error: Vout=%d, Vbcp_allow=%d", context->tag, samp_value.voltage_out, context->running_data.a->msg_bcp.allow_voltage);
                context->running_data.a->stop_ticks = OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVO_STOP_FAULT;
                return OpenChaoJi_gbt27930_a_evcc_stop_failed(context, OPENCHAOJI_GBT27930_A_END_CODE_EVCC_FAULT, OPENCHAOJI_GBT27930_A_END_REASON_EVCC_ERROR_VOLTAGE);
            }
        #endif
        }

        if (context->current_module_status_id > OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_HANDSHAKE_S0_INIT)
        {
            // GB/T 27930 附录A.2
            if (context->running_data.a->msg_cem_ok)
            {
                LOG_ERR("[%d]SECC Communicate Error", context->tag);
                context->running_data.a->stop_ticks = OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVO_STOP_TIMEOUT;
                return OpenChaoJi_gbt27930_a_evcc_rcvd_cem(context);
            }
        }

        // TODO: 故障代码、故障条件判断
        // GB/T 18487.1 B.4.7.2 车辆出现不能继续充电的故障

        // GB/T 27930 11.3.4 BSM电池状态异常
        union OpenChaoJi_evcc_hal_batt_state batt_state = OpenChaoJi_evcc_hal_get_batt_state(context->hal_handle);
        if (batt_state.all & 0x0FFF)
        {
            LOG_ERR("[%d]EVCC State Error: batt_state=0x%04x", context->tag, batt_state.all);
            context->running_data.a->stop_ticks = OPENCHAOJI_GBT27930_A_PID_TIMEOUT_EVCC_TVO_STOP_FAULT;
            return OpenChaoJi_gbt27930_a_evcc_stop_failed(context, OPENCHAOJI_GBT27930_A_END_CODE_EVCC_FAULT, OPENCHAOJI_GBT27930_A_END_REASON_EVCC_FAULT_OTHER);
        }
    }

    // 时钟同步
    if (context->current_module_status_id > OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CONFIG_S0_INIT && \
        context->current_module_status_id < OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S0_INIT)
    {
        if (context->running_data.a->msg_cts_ok)
        {
            context->running_data.a->msg_cts_ok = 0;
            LOG_NOTICE("[%d]SECC cts received", context->tag);
            // 时钟同步
            if (!context->running_data.a->config.time_sync)
            {
                struct tm time_info;
                time_info.tm_sec = OpenChaoJi_gbt27930_a_evcc_bcd_to_hex(context->running_data.a->msg_cts.time[0]);
                time_info.tm_min = OpenChaoJi_gbt27930_a_evcc_bcd_to_hex(context->running_data.a->msg_cts.time[1]);
                time_info.tm_hour = OpenChaoJi_gbt27930_a_evcc_bcd_to_hex(context->running_data.a->msg_cts.time[2]);
                time_info.tm_mday = OpenChaoJi_gbt27930_a_evcc_bcd_to_hex(context->running_data.a->msg_cts.time[3]);
                time_info.tm_mon = OpenChaoJi_gbt27930_a_evcc_bcd_to_hex(context->running_data.a->msg_cts.time[4]) - 1;
                time_info.tm_year = OpenChaoJi_gbt27930_a_evcc_bcd_to_hex(context->running_data.a->msg_cts.time[5]) * 100;
                time_info.tm_year += OpenChaoJi_gbt27930_a_evcc_bcd_to_hex(context->running_data.a->msg_cts.time[6]);
                time_info.tm_year -= 1900;
                time_info.tm_isdst = -1;

                if (OpenChaoJi_evcc_hal_set_time(context->hal_handle, mktime(&time_info)) == 0)
                {
                    LOG_NOTICE("[%d]time_sync succeed", context->tag);
                    context->running_data.a->config.time_sync = 1;
                }
                else
                {
                    LOG_ERR("[%d]time_sync failed", context->tag);
                }
            }
        }
    }

    if (context->current_module_status_id >= OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_CHARGE_S5_EV_STOP && \
        context->current_module_status_id <= OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_ERROR_S2_BEM)
    {
        // GB/T 18487.1-2023 B.4.6-B.4.7 停机泄放
        if (context->running_data.a->stop_status < OPENCHAOJI_GBT27930_A_EVCC_STOPPING_STATUS_FINISHED)
        {
            LOG_DEBUG("[%d]stopping", context->tag);
            OpenChaoJi_gbt27930_a_evcc_stopping(context);
        }
    }

    return context->current_module_status_id;
}

/**
 * 收发数据的通用处理方法
 * 收是在执行所有system操作前统一执行, 用于同步对端状态
 * 发是在执行所有system后统一执行, 用于把本方状态同步给对端
*/
void OpenChaoJi_gbt27930_a_evcc_data_read_func(struct OpenChaoJi_evcc_context * context)
{
    // 先把对端数据都收过来
    OpenChaoJi_evcc_utility_session_service_try_recv(context->context_session);

    // 读空缓冲区, 解析到system数据处理区
    struct OpenChaoJi_utility_data_buff_recv_data recv_data;
    while (OpenChaoJi_evcc_utility_session_data_read(context->context_session, &recv_data) == 0)
    {
        OpenChaoJi_gbt27930_a_evcc_parse_data(context, &recv_data);
        if (!recv_data.recv_data.src_free)
        {
            OpenChaoJi_os_free(recv_data.recv_data.data);
        }
    }
}
void OpenChaoJi_gbt27930_a_evcc_data_write_func(struct OpenChaoJi_evcc_context * context)
{
    OpenChaoJi_evcc_utility_session_service_try_send(context->context_session);
}

/**
 * 启停充电/获取充电等方法, 供App调用
*/
int OpenChaoJi_gbt27930_a_evcc_app_start_func(struct OpenChaoJi_evcc_context * context, struct OpenChaoJi_evcc_app_start_parameter * app_start_parameter)
{
    LOG_ALERT("[%d]evcc_app_start_func", context->tag);

    context->running_data.a->app_start_parameter = *app_start_parameter;
    context->app_permit_charge = 1;
    return 0;
}
int OpenChaoJi_gbt27930_a_evcc_app_stop_func(struct OpenChaoJi_evcc_context * context)
{
    LOG_ALERT("[%d]evcc_app_stop_func", context->tag);

    context->app_permit_charge = 0;
    return 0;
}
int  OpenChaoJi_gbt27930_a_evcc_app_get_status_func(struct OpenChaoJi_evcc_context * context, struct OpenChaoJi_evcc_context_status * status)
{
    status->current_module_status_id = context->current_module_status_id;

    return 0;
}


int OpenChaoJi_evcc_create_system_gbt27930_a(struct OpenChaoJi_evcc_context * context)
{
    /* 注册evcc系统, 生成evcc系统模块状态表 */
    context->evcc_gbt27930_system_a = OpenChaoJi_os_malloc(sizeof(struct OpenChaoJi_evcc_gbt27930_system));
    if (context->evcc_gbt27930_system_a == NULL)
    {
        goto FAILED_CREATE;
    }
    memset(context->evcc_gbt27930_system_a, 0x00, sizeof(struct OpenChaoJi_evcc_gbt27930_system));

    context->evcc_gbt27930_system_a->name = "EVCC_GBT27930_A";

    context->evcc_gbt27930_system_a->module_array = OpenChaoJi_os_malloc(OPENCHAOJI_GBT27930_A_MODULE_NUM * sizeof(struct OpenChaoJi_evcc_module *));
    if (context->evcc_gbt27930_system_a->module_array == NULL)
    {
        goto FAILED_CREATE;
    }
	memset(context->evcc_gbt27930_system_a->module_array, 0x00, OPENCHAOJI_GBT27930_A_MODULE_NUM * sizeof(struct OpenChaoJi_evcc_module *));
	context->evcc_gbt27930_system_a->module_array_len = OPENCHAOJI_GBT27930_A_MODULE_NUM;

    context->evcc_gbt27930_system_a->module_array[OPENCHAOJI_GBT27930_A_MODULE_IDLE]        = &c_gbt27930_a_evcc_module_idle;
    context->evcc_gbt27930_system_a->module_array[OPENCHAOJI_GBT27930_A_MODULE_TRIGGER]     = &c_gbt27930_a_evcc_module_trigger;
    context->evcc_gbt27930_system_a->module_array[OPENCHAOJI_GBT27930_A_MODULE_HANDSHAKE]   = &c_gbt27930_a_evcc_module_handshake;
    context->evcc_gbt27930_system_a->module_array[OPENCHAOJI_GBT27930_A_MODULE_CONFIG]      = &c_gbt27930_a_evcc_module_config;
    context->evcc_gbt27930_system_a->module_array[OPENCHAOJI_GBT27930_A_MODULE_CHARGE]      = &c_gbt27930_a_evcc_module_charge;
    context->evcc_gbt27930_system_a->module_array[OPENCHAOJI_GBT27930_A_MODULE_END]         = &c_gbt27930_a_evcc_module_end;
    context->evcc_gbt27930_system_a->module_array[OPENCHAOJI_GBT27930_A_MODULE_ERROR]       = &c_gbt27930_a_evcc_module_error;

    context->evcc_gbt27930_system_a->sub_module_func = OpenChaoJi_gbt27930_a_evcc_sub_module_func;
    context->evcc_gbt27930_system_a->data_read_func = OpenChaoJi_gbt27930_a_evcc_data_read_func;
    context->evcc_gbt27930_system_a->data_write_func = OpenChaoJi_gbt27930_a_evcc_data_write_func;
    context->evcc_gbt27930_system_a->app_start_func = OpenChaoJi_gbt27930_a_evcc_app_start_func;
    context->evcc_gbt27930_system_a->app_stop_func = OpenChaoJi_gbt27930_a_evcc_app_stop_func;
    context->evcc_gbt27930_system_a->app_get_status_func = OpenChaoJi_gbt27930_a_evcc_app_get_status_func;

    /* 创建运行时数据 */
    context->running_data.a = OpenChaoJi_os_malloc(sizeof(struct OpenChaoJi_evcc_gbt27930_a_data));
    if (context->running_data.a == NULL)
    {
        goto FAILED_CREATE;
    }
    // memset(context->running_data.a, 0x00, sizeof(struct OpenChaoJi_evcc_gbt27930_a_data));

    OpenChaoJi_gbt27930_a_evcc_running_data_reset(context);

    context->current_module_status_id = OPENCHAOJI_GBT27930_A_EVCC_STATUS_ID_IDLE_S0_IDLE;
    context->current_status_ticks = OpenChaoJi_os_get_ticks();

    return 0;

FAILED_CREATE:
    OpenChaoJi_evcc_destory_system_gbt27930_a(context);

    return -1;
}

/**
 * @brief: 销毁系统上下文
 * @param {OpenChaoJi_evcc_context *} context 系统上下文指针
 * @return {*}
 */
void OpenChaoJi_evcc_destory_system_gbt27930_a(struct OpenChaoJi_evcc_context * context)
{
    if (context->evcc_gbt27930_system_a != NULL)
    {
        if (context->evcc_gbt27930_system_a->module_array == NULL)
        {
            OpenChaoJi_os_free(context->evcc_gbt27930_system_a->module_array);
        }

        OpenChaoJi_os_free(context->evcc_gbt27930_system_a);
    }

    if (context->running_data.a != NULL)
    {
        OpenChaoJi_os_free(context->running_data.a);
    }
}

/**********************************以下为A类系统报文解析函数*******************************************/
/**
 * @brief  解析接收报文
 *
 * @param  context 系统上下文指针，包含必要的环境信息。
 * @param  recv_data 接收的数据结构
 * @return 成功返回0，失败返回-1。
 */
int OpenChaoJi_gbt27930_a_evcc_parse_data(struct OpenChaoJi_evcc_context * context, struct OpenChaoJi_utility_data_buff_recv_data * recv_data)
{
	if(recv_data->tag.gbt.msg_type != OPENCHAOJI_GBT27930_SYSTEM_A_MSG)
	{
        LOG_ERR("Not MsgType GBT-A");
        goto PARSE_FAILED;
    }

    struct OpenChaoJi_gbt27930_a_msg msg;
    if (!OpenChaoJi_gbt27930_a_msg_decode(&msg, recv_data->tag.gbt.pf, recv_data->recv_data.data, recv_data->recv_data.len, context->running_data.a->protocol_version))
    {
        goto PARSE_FAILED;
    }

    bool changed = false;
    switch(recv_data->tag.gbt.pf)
    {
    case OPENCHAOJI_GBT27930_A_PGN_CHM:
        changed = OpenChaoJi_gbt27930_a_msg_cmpcpy_chm(context->tag
            , &context->running_data.a->msg_chm
            , &msg.msg.chm
        );
        if (!context->running_data.a->msg_chm_ok)
        {
            LOG_WARNING("[%d]msg_chm_ok", context->tag);
            context->running_data.a->msg_chm_ok = 1;
            changed = true;
        }
        break;

    case OPENCHAOJI_GBT27930_A_PGN_CRM:
        changed = OpenChaoJi_gbt27930_a_msg_cmpcpy_crm(context->tag
            , &context->running_data.a->msg_crm
            , &msg.msg.crm
        );
        if (!context->running_data.a->msg_crm_ok)
        {
            LOG_WARNING("[%d]msg_crm_ok", context->tag);
            context->running_data.a->msg_crm_ok = 1;
            changed = true;
        }
        break;

    case OPENCHAOJI_GBT27930_A_PGN_CTS:
        changed = OpenChaoJi_gbt27930_a_msg_cmpcpy_cts(context->tag
            , &context->running_data.a->msg_cts
            , &msg.msg.cts
        );
        if (!context->running_data.a->msg_cts_ok)
        {
            LOG_WARNING("[%d]msg_cts_ok", context->tag);
            context->running_data.a->msg_cts_ok = 1;
            changed = true;
        }
        break;

    case OPENCHAOJI_GBT27930_A_PGN_CML:
        changed = OpenChaoJi_gbt27930_a_msg_cmpcpy_cml(context->tag
            , &context->running_data.a->msg_cml
            , &msg.msg.cml
        );
        if (!context->running_data.a->msg_cml_ok)
        {
            LOG_WARNING("[%d]msg_cml_ok", context->tag);
            context->running_data.a->msg_cml_ok = 1;
            changed = true;
        }
        break;

    case OPENCHAOJI_GBT27930_A_PGN_CRO:
        changed = OpenChaoJi_gbt27930_a_msg_cmpcpy_cro(context->tag
            , &context->running_data.a->msg_cro
            , &msg.msg.cro
        );
        if (!context->running_data.a->msg_cro_ok)
        {
            LOG_WARNING("[%d]msg_cro_ok", context->tag);
            context->running_data.a->msg_cro_ok = 1;
            changed = true;
        }
        break;

    case OPENCHAOJI_GBT27930_A_PGN_CCS:
        changed = OpenChaoJi_gbt27930_a_msg_cmpcpy_ccs(context->tag
            , &context->running_data.a->msg_ccs
            , &msg.msg.ccs
        );
        if (!context->running_data.a->msg_ccs_ok)
        {
            LOG_INFO("[%d]msg_ccs_ok", context->tag);
            context->running_data.a->msg_ccs_ok = 1;
            // changed = true; // 周期数据, 变更时打印
        }
        break;

    case OPENCHAOJI_GBT27930_A_PGN_CST:
        changed = OpenChaoJi_gbt27930_a_msg_cmpcpy_cst(context->tag
            , &context->running_data.a->msg_cst
            , &msg.msg.cst
        );
        if (!context->running_data.a->msg_cst_ok)
        {
            LOG_WARNING("[%d]msg_cst_ok", context->tag);
            context->running_data.a->msg_cst_ok = 1;
            changed = true;
        }
        break;

    case OPENCHAOJI_GBT27930_A_PGN_CSD:
        changed = OpenChaoJi_gbt27930_a_msg_cmpcpy_csd(context->tag
            , &context->running_data.a->msg_csd
            , &msg.msg.csd
        );
        if (!context->running_data.a->msg_csd_ok)
        {
            LOG_WARNING("[%d]msg_csd_ok", context->tag);
            context->running_data.a->msg_csd_ok = 1;
            changed = true;
        }
        break;

    case OPENCHAOJI_GBT27930_A_PGN_CEM:
        changed = OpenChaoJi_gbt27930_a_msg_cmpcpy_cem(context->tag
            , &context->running_data.a->msg_cem
            , &msg.msg.cem
        );
        if (!context->running_data.a->msg_cem_ok)
        {
            LOG_WARNING("[%d]msg_cem_ok", context->tag);
            context->running_data.a->msg_cem_ok = 1;
            changed = true;
        }
        break;

    default:
        LOG_ERR("[%d]Unknown PID[%02X]", context->tag, recv_data->tag.gbt.pf);
        goto PARSE_FAILED;
    }

    // 接收数据发生变化必须打出完整报文, 打印级别是INFO则把所有报文打印出来
    if ((changed) || ((OpenChaoJi_debug_get_log_level() & DBGL_INFO) != 0))
    {
        // 周期性报文, 即使INFO级别也不打印, 只变化才打印
        if (!changed && !s_gbt_a_public_debug_enable)
        {
            return 0;
        }

        OpenChaoJi_gbt27930_a_msg_log(&msg);
        if ((OpenChaoJi_debug_get_log_level() & DBGL_INFO) != 0)
        {
            LOG_DATA_CHANGE("<-[%02X][%d]", msg.pid, recv_data->recv_data.len);
            LOG_DATA_BUFF_CHANGE(recv_data->recv_data.data, recv_data->recv_data.len);
        }
    }

	return 0;

PARSE_FAILED:
    LOG_ERR("[%d]Invalid MsgFromSecc", context->tag);
    LOG_BUFF_ERR(recv_data->recv_data.data, recv_data->recv_data.len);
    return -1;
}

#endif

